/*

CLASS {Expr|ession},
	RECURSIVE, UNTESTED, DESTRUCTORS, BITWISE :

IMPORT: {Compiler}, {Parser}, {Text_parser}, {Function}, {Variable}, {Type},
		{Statement}, {For}, {System_functions}, {String_functions},
		{Assignment}, {Table}, {Localize_str}, {E_op} ;
*/

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

namespace AL4Compiler
{
    public class Expression
    {
        /*

        ENUMERATION {operation}:
			'UNKNOWN',					//0
			'BINARY|OP',				//1
			'FUN|CTION_CALL', 			//2
			'BASE_FUN|CTION_CALL',		//3
			'SYSTEM_FUN|CTION_CALL',	//4
            'VAR|IABLE',				//5
            'INDEX|ING_ARRAY_ITEM',		//6
            'FIELD|_OF_CLASS',			//7
            'NEW_OBJ|ECT',				//8
            'ARRAY|_OF_VALUES',			//9
            'AS|_OBJECT_OF_CLASS',		//10
            'CONST|ANT',				//11
            'INT2REAL|_CONVERSION',		//12
            'NOT_B|ITWISE',				//13
            'NOT|_LOGICAL',				//14
            'NEG|ATIVE_RESULT' .		//15
            
        ENUMERATION {bin|ary_operation}:
			'UNDEFINED',
			'PLUS|_ADD', 		//1
			'MINUS|_SUBTRACT',	//2
            'MULT|IPLY', 		//3
            'DIV|ISION',      		//4
            'REST|_OF_DIVISION',   	//5
            'AND_B|ITWISE',         //6
            'OR_B|ITWISE',          //7
            'XOR_B|ITWISE',			//8
            'AND|_LOGICAL',			//9
            'OR|_LOGICAL',       	//10
            'EQUAL|_COMPARE',	//11
            'LESS|_COMPARE',	//12
            'GREATER|_COMPARE',	//13
            'NOT_EQ|UAL',       //14
            'LESS_OR_EQ|UAL',	//15
            'GREATER_OR_EQ|UAL',		//16
            'IN|_ARRAY',				//17
            'NOT_IN|_ARRAY',   			//18
            'LIKE|_STRING',				//19
            'UNLIKE|_STRING',			//20
            'CONCAT|ENATE_STRINGS' .	//21
            
        {operation} Operation|_kind
        -------------------------------- 'binary operation details'
        {Expr}      Arg1_|ument_
        {Expr}      Arg2_|ument_
        {Expr}      Arg3_|end_of_range_
        {bin}       Sign|_of_operation
        -------------------------------- 'function call details'
        {Fun}       Fun_|ction_to_call_
        
        {Expr}      This_|object_passes_as_a_parameter_
        {Var}       Var_arg|ument
        {Expr}      Items_|of_array_or_params_for_fun_call_[]
        BOOL		Is_param|eter_to_pass_to_a_function
        -------------------------------- 'for interpreter'
        INT			Int_items[]
        STR			Str_items[]
        -------------------------------- 'NEW operation & Record init'
        {Type}      Type_obj_
        {Statement} Assignments_[]
        {Statement} Before_assign_|ments_[]
        {Expr}      Array_|to_add_to_
        {Expr}      Owned_|by_object_
        -------------------------------- 'compiling:'
        INT         At_line|_of_source_dummy
        INT         At_pos|ition
        BOOL        Is_const|ant_expression_can_be_precalculated
        INT         Total_const|ant_expression_index
        BOOL        Calculated|_from_constant_expression
        STR         Replace_index|_set_while_optimization
        ----------------------------- 'when expression represents TRAP function'
        {Expr}		Original_variable_expr_
        -------------------------------- 'for localized string constant:'
        STR         Localize_n|ame_of_string
        INT         Localize_i|ndex INDEXING {Expr}
        -------------------------------------- 'passing STORE parameter'
        BOOL        Pass_by_ref|erence
        -------------------------------------- 'optimize for * index operation'
        BOOL        Is_star_operation
        */

        private static int CNT_all_expression;
        private int INDEX_all_expression;
        public Expression()
        {
            INDEX_all_expression = ++CNT_all_expression;
            if (INDEX_all_expression == 28507)
            { }
        }

        public enum Operation_kind { UNKNOWN, BINARY, FUN, VAR, INDEX, FIELD, NEW, ARRAY, AS, CONST };

        public static string[] Operation_kind_names = { "UNKNOWN", "BINARY", "FUN", "VAR", "INDEX", "FIELD", 
                                                        "NEW", "ARRAY", "AS", "CONST" }; 

        public enum Bin
        {
            PLUS, MINUS, MULT, DIV, REST, AND_B, OR_B, XOR_B,
            AND, OR, EQUAL, LESS, GREATER, NOT_EQ, LESS_OR_EQ, GREATER_OR_EQ,
            IN, NOT_IN, CONCAT
        };

        public static string[] Bin_names = new string[] {
            "PLUS", "MINUS", "MULT", "DIV", "REST", "AND_B", "OR_B", "XOR_B",
            "AND", "OR", "EQUAL", "LESS", "GREATER", "NOT_EQ", "LESS_OR_EQ", "GREATER_OR_EQ",
            "IN", "NOT_IN", "CONCAT" };

        public bool Neg;
        public bool Not;
        public bool Inc;
        public bool Dec;
        public Operation_kind Operation;

        //------------------------------- 'binary operation details'
        public Expression Arg1_;
        public Expression Arg2_;
        public Expression Arg3_;
        public Bin Sign;
        //------------------------------- 'function call'
        public Function Fun_;
        public Expression This_;
        public List<Expression> Items_ = new List<Expression>();
        public Variable Var_arg;
        //------------------------------- 'NEW operation details'
        public Type Type_obj_ = null;
        public List<Statement> Assignments_ = new List<Statement>();
        public Expression Array_;
        public Expression Owned_;
        //------------------------------- 'compiling:'
        public int At_line;
        public int At_pos;
        //-------------------------------- 'for localized string constant:'
        public string Localize_n;
        public int Localize_i;

        /*
        
        METHOD Is_array ==> BOOL, RECURSIVE :
            CASE Operation ?
                ['VAR', 'CONST', 'FIELD']:
                    RESULT = Var_arg.Is_array
                    
                ['ARRAY']: RESULT = TRUE 
                
                ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ', 'AS',
                 'UNKNOWN', 'NOT_B', 'NOT', 'NEG']:
                    
                    RESULT = FALSE
                    
                ['INDEX']: RESULT = Arg1_.Is_array 
                		   RESULT &&= Arg3_ != NONE
                
                ['INT2REAL']: RESULT = FALSE ; .
        */
        public bool Is_array()
        {
            switch (Operation)
            {
                case Operation_kind.VAR:
                case Operation_kind.CONST:
                case Operation_kind.FIELD:
                    return Var_arg != null && Var_arg.Is_array;
                case Operation_kind.ARRAY:
                    return true;
            }
            return false;
        }

        /*
        
        METHOD Is_fixed ==> BOOL :
            CASE Operation ?
                ['VAR', 'CONST', 'FIELD']:
                    RESULT = Var_arg.Is_array && Var_arg.Is_fixed
                ['ARRAY']: RESULT = TRUE
                
                ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ', 'AS',
                 'UNKNOWN', 'NOT_B', 'NOT', 'NEG']:
                    
                    RESULT = FALSE
                    
                ['INDEX']: RESULT = Arg1_.Is_array 
                		   RESULT &&= Arg3_ != NONE
                		   
                ['INT2REAL']: RESULT = FALSE ; .
                
        METHOD Is_temp_fixed ==> BOOL :
            CASE Operation IN ['VAR', 'CONST', 'FIELD'] ?
                    RESULT = Var_arg.Is_array && Var_arg.Is_temp_fixed ; .

        */
        public bool Is_fixed()
        {
            switch (Operation)
            {
                case Operation_kind.VAR:
                case Operation_kind.CONST:
                    return Var_arg.Is_array && Var_arg.Is_fixed;
                case Operation_kind.ARRAY:
                    return true;
            }
            return false;
        }

        /*
        
        METHOD Type_expr|ession ==> {Type}, RECURSIVE :
            CASE Type_obj_ != NONE ? 
                 RESULT = Type_obj_ ==> ;
            CASE Operation ?
                ['FUN', 'BASE_FUN', 'SYSTEM_FUN']: RESULT = Fun_.Result.Type_
                	CASE Fun_.Modifiers['TRAP_FUN'] ?
                	     RESULT = Fun_.Trap_field.Type_ ;
                	CASE RESULT.Kind == 'ENUM' && RESULT.Names[0] == "{}" ?
                	     CASE Fun_.Names[0] IN [
                	     	  "Prev", "Next", "First", "Last"]
                	     	  ?
                	          RESULT = Items_[0].Type_expr ;
                	;
                ['CONST', 'FIELD']: RESULT = Var_arg.Type_
                ['VAR']: RESULT = Var_arg.Type_
                ['ARRAY']: RESULT = Type_obj_
                ['INDEX']: RESULT = Arg1_.Type_expr
                ['INT2REAL']: RESULT = Type_obj_ //comp(Parse).TYPE_REAL
                ['NEW_OBJ', 'BINARY', 'AS']: RESULT = Type_obj_
                ['NOT_B', 'NOT', 'NEG']: RESULT = Arg1_.Type_expr
                ['UNKNOWN']: RESULT = NONE ; .
                
        METHOD From_type({Type} T|ype_check_belonging_to) ==> BOOL :
			CASE ?
			[Operation =='VAR']  ? RESULT = Var_arg.In_type_ == T
			[Operation =='FIELD']? RESULT = Arg1_.Type_expr == T ; .
        */
        public Type Type_expr()
        {
            if (Type_obj_ != null) return Type_obj_;
            switch (Operation)
            {
                case Operation_kind.FUN:
                    return Fun_ != null && Fun_.Result != null ? Fun_.Result.Type_ : null;
                case Operation_kind.VAR:
                case Operation_kind.CONST:
                case Operation_kind.FIELD:
                    if (Var_arg != null) return Var_arg.Type_;
                    else return null;
                case Operation_kind.ARRAY:
                    return Type_obj_;
                case Operation_kind.INDEX:
                    return Arg1_.Type_expr();
                case Operation_kind.NEW:
                case Operation_kind.BINARY:
                case Operation_kind.AS:
                    return Type_obj_;
                case Operation_kind.UNKNOWN:
                    return null;
            }
            return null;
        }

        /*
        
        METHOD Is_read_only ==> BOOL, RECURSIVE :
            CASE Operation ?
            ['VAR']: RESULT = Var_arg.Modifiers[{var_mod}.'READ']
                RESULT ||= Var_arg.Is_loop && Var_arg.For_.Array == NONE
                
            ['FIELD']: {Parser} p|arser_of_class = Var_arg.In_type_.Parse
                {Type} cc|lass_current = comp(p).Current_class
                RESULT = Var_arg.Modifiers[{var_mod}.'READ']
                
                RESULT ||= !Var_arg.Is_public && (
                    !cc.Is_descend(Var_arg.In_type_, comp(p)))
                    
            ['INDEX']: RESULT = Arg1_.Is_read_only
            
            ['INT2REAL']: RESULT = Arg1_.Is_read_only
            
            ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ', 'ARRAY',
             'CONST', 'AS', 'UNKNOWN', 'NOT_B', 'NOT', 'NEG']:
                
				RESULT = TRUE 
            ; .
        */
        public bool Is_read_only()
        {
            bool Result = false;
            switch (Operation)
            {
                case Operation_kind.VAR:
                    Result = Var_arg.Modifiers[(int)Variable.Var_mod.READ] 
                        || Var_arg.Is_loop_var;
                    break;
                case Operation_kind.FIELD:
                    Parser p = Var_arg.In_class_.Parse;
                    Type cc = p.Compiler_.Current_class;
                    Result = Var_arg.Modifiers[(int)Variable.Var_mod.READ] 
                        || !Var_arg.Is_public() && !cc.Is_descendant_of(Var_arg.In_class_, p.Compiler_);
                    break;
                case Operation_kind.INDEX:
                    Result = Arg1_.Is_read_only();
                    break;
                default: Result = true;
                    break;
            }
            return Result;
        }

        /*
        
        METHOD Is_new|_object_created ==> BOOL :
            RESULT = Operation == 'NEW_OBJ'
            RESULT ||= Fun_.Modifiers['NEW'] .
            
METHOD Has_function_calls ==> BOOL, RECURSIVE :
	CASE Operation ?
	['UNKNOWN', 'VAR', 'AS', 'CONST']: NONE
	['BINARY', 'INDEX', 'FIELD', 'ARRAY']:
		RESULT = Arg1_.Has_function_calls
		RESULT ||= Arg2_.Has_function_calls
		RESULT ||= Arg3_.Has_function_calls
		FOR it IN Items_[] :
		    RESULT ||= it.Has_function_calls ;
	['FUN', 'BASE_FUN', 'SYSTEM_FUN']: RESULT = TRUE
	['NEW_OBJ']:
		FOR a IN Assignments_[]:
		    RESULT = a.Has_function_calls
		    CASE RESULT ? ==> ;
		;
	['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
		RESULT = Arg1_.Has_function_calls ; .
        */
        public bool Is_new()
        {
            return Operation == Operation_kind.NEW ||
                Operation == Operation_kind.FUN &&
                Fun_.Modifiers[(int)Function.Fun_mod.NEW];
        }

        /*
        
        FUNCTION Recognize_typed({Parser} Parse|_source,
            {Type}.{kind_type} K|ind_of_type) ==> {Expr}, NEW
            :
            -------------------------------------- 'Recognize'
            INT pos|ition = Parse.Pos
            RESULT = Recognize(Parse), >> comp(Parse).Current_fun.All_expr[]
            //DEBUG: STR rest_1|_of_line = Parse.Rest_of_line ; 
            
            RESULT = RESULT.Chain_operations(Parse, FALSE)
            //DEBUG: STR rest_2|_of_line = Parse.Rest_of_line ;
            -------------------------------------- 'Compare type with needed'
            CASE RESULT.Type_expr == NONE
            	 && !Parse.Compiler.Current_fun.Dummy_compile
            	 ?
            	 PUSH Parse.Pos = pos :
                    Parse.Err("Waiting expression of type"._Ewait " " K.Name
                    " " ("but there is no value found"._Ebut ) 
                    ": " Parse.Next20) ==> ;
            ;
            CASE ?
            [K == 'REAL' && RESULT.Type_expr.Kind == 'INT'] ?
                 CASE RESULT.Operation == 'CONST' ?
                      RESULT.Var_arg.Real_c = RESULT.Var_arg.Int_c
                      RESULT.Var_arg.Type_ = Parse.Compiler.TYPE_REAL ;
                 ==> ;
            CASE RESULT.Type_expr.Kind != K 
            	 && !Parse.Compiler.Current_fun.Dummy_compile
            	 ?
                PUSH Parse.Pos = pos :
                    Parse.Err("Waiting expression of type"._Ewait2 " " K.Name
                    " " ("but expression of type"._Ebut2 )
                    " " RESULT.Type_expr.Kind.Name
                    " " ("is found"._Efound ) ": " Parse.Next20) ;
            ; .
        */
        public static Expression Recognize_typed(Parser Parse, Type.Kind_type K)
        {
            int pos = Parse.Pos;
            Expression Result = Recognize(Parse);
            if (Result != null && Result.Type_expr() != null && Result.Type_expr().Kind != K)
            {
                int sav = Parse.Pos;
                Parse.Pos = pos;
                try
                {
                    Type.Kind_type bu = Result.Type_expr().Kind;
                    int bi = (int)bu;
                    Parse.Err("Waiting expression of type " + Type.Kind_type_names[(int)K] +
                        " but expression of type " + Type.Kind_type_names[bi] +
                        " is found: " + Parse.Next20());
                }
                finally { Parse.Pos = sav; }
            }
            Result = Chain_operations(Result, Parse);
            return Result;
        }

        /*
        
        METHOD has_clone_in_chain ==> BOOL, RECURSIVE :
			FOR it IN Items_[] :
	        	CASE it.Operation=='SYSTEM_FUN'
	        		 && it.Fun_.System_fun=='SYSFUN_Clone'
	        		 ?
	        	     RESULT = TRUE ==> ;
	        	RESULT = it.has_clone_in_chain ; .
	        	
FUNCTION Recognize({Parser} Parse|_src) ==> {Expr},
    NEW, RECURSIVE
    :
    {Fun} cf|unction_current = comp(Parse).Current_fun
    ------------------------------------ 'Recognize expression'
    PUSH Parse.Ending_incl :
        {Expr} operands|_temp[]
        //{bin}  signs|_of_binary_operations[]
        {E_op} operations[]
        Parse.Skip_sp
        ---------------------- 'operand sign operand sign ... operand'
        FOR x|dummy IN [Parse.Pos TO Parse.Last] :
            Parse.Skip_sp

            INT start|_recognize_operand = Parse.Pos

            //DEBUG: STR rest_3|_of_line = Parse.Rest_of_line ;

            {Expr} oper|and_next = obtain_operand(Parse),
               >> cf.All_expr[]

            //DEBUG: STR rest_4|_of_line = Parse.Rest_of_line
            //<< rest_4 #NL
            //;

            oper.At_pos = start
            CASE oper == NONE ? BREAK x ;
            ----------- 'chain of .fun(...) or [index] or smth else'
            oper = oper.Chain_operations(Parse, FALSE),
                   >> cf.All_expr[]

            //DEBUG: STR rest_5|_of_line = Parse.Rest_of_line
            //<< "after chain: " rest_5 #NL
            //;

            CASE oper.has_clone_in_chain ?
                 Parse.Err("Any operations or functions should not be "
                 "applied to a cloned structure and a clone of a "
                 "structure should not be passed as a parameter"
                 ""._EOperationUnderClone)
            ;

            operands[] << oper
            ------------------- 'check for invalid = in expression'
            CASE ! cf.Left_side && (
                 ! Parse.Next_symbol("==") && Parse.Next_symbol("="))
                 ?
                 Parse.Err("Invalid operation = . May be == should be "
                 "there"._Einvalid ": " Parse.Next20)
            ;
            CASE Parse.End_of_expr ? BREAK x ;
            ------------------------------------------ '\fun\'
            //! opd op opd op ... opd \fun\ opd op opd op ... opd
            CASE Parse.Symbol("\") ?
                 INT pos_b|efore_exclamation = Parse.Pos
                 BOOL is_not|_operation = Parse.Symbol("!")
                 INT was_count_not = cf.Count_not
                 PUSH cf.Count_not :
                      CASE is_not ? cf.Count_not += 1 ;
                      {Expr} thv|ariable_this[]
                      {Fun} fn|ext_function = Scan_fun(Parse, thv[])
                      Parse.Wait("\")
                      CASE fn.Param[].Count != 2 ?
                           Parse.Err("Amount of parameters of a \function\"
                           " called such way must be equal to 2"
                           ""._EParamNot2 "(but " fn.Names[*]
                           " has " fn.Param[].Count.Str ")")
                      ;
                      CASE fn.Result==NONE ?
                           Parse.Err("Function used as a binary "
                           "\operation\ "
                           "has no result"._EnoResult2) ;
                      {Expr} lopd1|_left_operand_one = operands[0]
                      ---------------------------- 'if it is overloaded:'
                      FOR ov IN fn.Overloaded_[] :
                          CASE ?
                          [ov.Param[0].Type_.Kind
                           != lopd1.Type_expr.Kind] ?
                               CONTINUE ov
                          [lopd1.Type_expr.Kind=='CLASS'
                           && !lopd1.Type_expr.Is_descendant_of(
                           ov.Param[0].Type_, comp(Parse)) ] ?
                               CONTINUE ov
                          [lopd1.Type_expr.Kind=='STRUCTURE'
                           && lopd1.Type_expr != ov.Param[0].Type_]
                          ?
                               CONTINUE ov
                          ;
                          fn = ov
                          BREAK ov
                      ;
                      CASE fn.Overloaded_[].Count > 0 ?
                           Parse.Err("Could not select an appropriate "
                           "overloaded version of function by the "
                           "first parameter type"._ECouldNotSelectOverloaded)
                      ;
                      operations[] << {E_op}(Fun_= fn,
                        This_pass_= thv[0],
                        Is_not = cf.Count_not > was_count_not )

                      CASE operations[*].Is_not && (
                           fn.Result.Type_.Kind != 'BOOL')
                           ?
                           PUSH Parse.Pos = pos_b :
                           Parse.Err("'!' operation is not applicable"
                           ""._ENotApplicableNot) ;
                      ;
                 ;
            ELSE
                 -------------------------- 'next operation'
                 //DEBUG: STR rest_6|_of_line = Parse.Rest_of_line ;
                 operations[] << {E_op}(Sign= Parse.Binary_op)
                 //DEBUG: "op=" signs[*].Name #NL ;
                 CASE ?
                 [operations[*].Sign IN ['AND_B', 'OR_B', 'XOR_B']] ?
                      comp(Parse).Current_class.Detect('BITWISE')
                 [operations[*].Sign IN ['AND', 'OR']] ?
                      comp(Parse).And_or_operations_present = TRUE
                 ;
            ;
        ;
        CASE !to_single_operand(operands[], operations[], Parse) ? ==> ;
        RESULT = operands[0]
        -------------------------- 'for binary op, set Type_obj'
        CASE RESULT.Operation == 'BINARY' ?
             RESULT.Type_obj_ = RESULT.calculate_type(
                 comp(Parse)) ;
    ;
    ---------------------------------------- 'is a constant expression?'
    CASE !cf.Is_test && (
         "a" IN comp(Parse).Optimizations) && (
         RESULT.Is_constant_expr)
         ?
         RESULT.remove_children_from_const_expr(
            comp(Parse).Current_class)
         RESULT.Is_const = TRUE
         comp(Parse).Current_class.Constant_expr[] << RESULT
    ; .
            
        FUN to_single_operand(
        {Expr} operands[], {E_op}  operations[], 
        {Parser} Parse|_of_text)
        ==> BOOL
        	:
        	{Fun} cf|unction_current = comp(Parse).Current_fun
			CASE ?
            [operands[].Count == 0] ?
                Parse.Err("Waiting for expression but"._Ewait3 ":"
                " " Parse.Next20) ==>
            [operands[].Count >= 500] ?
                 Parse.Warn("Too many operands in an expression (can cause "
                 "problems compiling it due to a too deep "
                 "recursion)"._Wtoo ) //==>
            [operands[].Count > 1] ?
                FOR opd IN operands[] :
                    CASE opd.Type_expr == NONE ?
                         Parse.Err("Function not returning result used as "
                     "an operand in the expression"._EFunNoResultOperand) 
                    ;
                ;
            ;
            ------------------ 'fix concatenation of strings for <<'
            //CASE force_str ? 
            //     FOR isign IN [0 TO signs[].Count-1] :
            //         CASE signs[isign] != 'CONCAT' ? force_str = FALSE ;
            //     ;
            //;
            CASE cf.Compiling_output || cf.Is_test ? // || force_str ?
                 FOR isign INDEXING ({Expr},{E_op}) IN [
                 	 0 TO operations[].Count-1]
                 	 :
                 	 INT i_op|erand_corresponding INDEXING {Expr} = isign    
                     CASE operations[isign].Sign == 'CONCAT' 
                     	  && operands[i_op].Type_expr.Kind != 'STR'
                     	  ?
                          operands[i_op] = apply_S(operands[i_op], Parse)
                     ;
                     CASE operations[isign].Sign == 'CONCAT' 
                     	  && operands[i_op+1].Type_expr.Kind != 'STR'
                     	  ?
                          operands[i_op+1] 
                          = apply_S(operands[i_op+1], Parse)
                     ;
                 ;
            ;
            ----------------- 'convert chains a < b < ... < z'
            convert_chains_of_inequalities(operands[], operations[], Parse)
            ------------------------------------------ 'operations tree'
            FOR j_op IN [0 TO operations[].Count-1] :
                CASE operations[j_op].Fun_ != NONE ? 
                     operations[j_op].Priority = operations[j_op].Fun_.Priority 
                     CASE operations[j_op].Priority==0 ? 
                          operations[j_op].Priority=100 ;
                ELSE
                     {bin} sign|_to_get_priority = operations[j_op].Sign
                     INT pr|iority
                     CASE sign ? 
                     ['UNDEFINED']: NONE
                     ['OR']		: pr = 100 
                     ['AND']	: pr = 200 
                     ['EQUAL', 'LESS', 'GREATER', 'NOT_EQ', 'LESS_OR_EQ',
                      'GREATER_OR_EQ']	: 
                         pr = 300
                     ['LIKE', 'UNLIKE']	: pr = 400
                     ['IN', 'NOT_IN']	: pr = 400
                     ['CONCAT']	: pr = 500 
                     ['OR_B']	: pr = 600
                     ['AND_B', 'XOR_B']	: pr = 700
                     ['PLUS', 'MINUS']	: pr = 800
                     ['MULT', 'DIV', 'REST']: pr = 900
                     ;
                     operations[j_op].Priority = pr
                ;
            ;
            PUSH Parse.Ignore_errors = cf.Dummy_compile :
            	 Parse.Do_priorities( operands[], operations[] )
            ;
            CASE operands[].Count >= 2 ?
                Parse.Err("Internal error: "
                "expression is not reduced"._Einternal )
            ; 
            RESULT = TRUE .
            
        FUN Scan_fun(
        {Parser} Parse|_of_text, 
        {Expr} This_v|ariable[]) ==> {Fun}
            :
            {Fun} cf|unction_current = comp(Parse).Current_fun
            {Type} cc|ontex_class= Parse.Class_
        	CASE Parse.Symbol("{") ? 
        		 cc= cf.Class_.Find_type("{" Parse.Ident "}")     
        	     Parse.Wait("}")
        	     Parse.Wait(".")
        	     BOOL is_not|_operation = Parse.Symbol("!")
        	     CASE is_not ?
        	          CASE cf.Count_not > 0 ? 
        	               Parse.Err("Suspicious sequentional operations '!'"
        	               ""._ESuspectNotNot) ;
        	          cf.Count_not += 1 ;
        	     RESULT = cc.Find_fun(Parse.Ident, TRUE) 
        	     CASE !RESULT.Modifiers['STATIC'] ? 
        	          Parse.Err("Calling a method this way (not specifying "
        	          "THIS value) is inavalid"._EInvalidMethodCallWOThis) ;
        	     ==>
        	;
        	CASE Parse.Symbol("(") ? 
        	     INT k|_waiting_brackets = brackets_to_wait(Parse)
        	     {Expr} ex|pression_returning_a_field_TEMP = Recognize(Parse)
        	     CASE ex.Type_expr.Kind != 'CLASS' ? 
        	          Parse.Err("Only expression returning an object can be "
        	          "in parenthesis to specify the THIS value in form : "
        	          "\(object).Method\") ;
        	     FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
    			 Parse.Wait(")")
    			 This_v[] << ex
    			 Parse.Wait(".")
    			 is_not = Parse.Symbol("!")
        	     CASE is_not ?
        	          CASE cf.Count_not > 0 ? 
        	               Parse.Err("Suspicious sequentional operations '!'"
        	               ""._ESuspectNotNot2) ;
        	          cf.Count_not += 1 ;
    			 RESULT = ex.Type_expr.Find_fun(Parse.Ident, TRUE) ==>
        	;
        	STR f_name|_function = Parse.Ident
        	RESULT = cc.Find_fun(f_name, TRUE)
        	CASE !RESULT.Modifiers['STATIC'] ? 
        		 CASE cf.Modifiers['STATIC'] ? 
        		      Parse.Err("Calling a method out of an object context"
        		      ""._EOutOfCVontext) ;
        	     This_v[] << comp(Parse).THIS_expr ; .

            
        FUN convert_chains_of_inequalities(
        {Expr} operands[], {E_op} operations[], {Parser} Parse|_source)
        	:
        	INT skip_down|_until = operations[].Count
        	FOR i IN [operations[].Count-1 DOWNTO 1] :
        	    CASE i > skip_down ? CONTINUE i ;
        	    CASE operations[i].Sign !IN [
        	         'EQUAL', 'LESS', 'GREATER', 'NOT_EQ',
        	         'LESS_OR_EQ', 'GREATER_OR_EQ']
            		 ?
        	         CONTINUE i ;
        	    skip_down = 0
        	    BOOL found|_sequential_op = FALSE
        	    FOR j INDEXING({E_op},{Expr}) IN [i-1 DOWNTO 0] :
        	    	CASE operations[j].Sign IN ['AND', 'OR'] ?
        	    	     skip_down = j
        	    	     BREAK j, CONTINUE i ;
        	        CASE operations[j].Sign !IN [
        	             'EQUAL', 'LESS', 'GREATER', 'NOT_EQ',
            		 	 'LESS_OR_EQ', 'GREATER_OR_EQ']
            		 	 ?
        	             CONTINUE j ;
        	        DONE 
        	        INT start|_from = j + 1
        	        skip_down = j
        	        found = TRUE
        	        BREAK j ;
        	    CASE !found ? ==> ;
        	    ---------- 'convert a < b + c < d --> a < b + c && b + c < d'
        	    {Fun} c_f|unction_current = Parse.Compiler.Current_fun
        	    {bin} copy_signs[]
        	    copy_signs[].Clear
        	    {Expr} copy_op|erands[]
        	    copy_op[].Clear
        	    FOR j IN [start TO i-1] : copy_signs[] << operations[j].Sign ;     
        	    FOR k INDEXING {Expr} IN [start TO i] : 
        	        copy_op[] << Duplicate_expr(operands[k], c_f) ;
        	    {E_op} op_and|_operation = {E_op}(Sign='AND'), OWNED BY c_f
        	    operations[].Insert(start, op_and)
        	    FOR j IN [0 TO copy_signs[].Count-1] :
        	    	{E_op} op_copy|_operation = {E_op}( Sign= copy_signs[j]),
        	    		OWNED BY c_f
        	    		 
        	        operations[].Insert(start+j, op_copy) ;
        	    FOR j IN [0 TO copy_op[].Count-1] :
        	        operands[].Insert(start + j, copy_op[j]) ;
        	; .
        	        
        	             
        FUN Duplicate_expr|ession(
        {Expr} S|ource_expression, {Fun} Curf|unction) ==> {Expr}, 
        RECURSIVE
            :
            CASE S == NONE ? ==> ;
                 
            temp|_result = {Expr}(Operation= S.Operation, Sign= S.Sign), 
            	OWNED BY Curf
            	
            RESULT = temp
            -------- '1'
            RESULT.Arg1_= Duplicate_expr(S.Arg1_, Curf)
            RESULT.Arg2_= Duplicate_expr(S.Arg2_, Curf)
            RESULT.Arg3_= Duplicate_expr(S.Arg3_, Curf)
            RESULT.This_= Duplicate_expr(S.This_, Curf)
            RESULT.Array_= Duplicate_expr(S.Array_, Curf)
            RESULT.Owned_= Duplicate_expr(S.Owned_, Curf)
            --------- '2'
            RESULT.Fun_= S.Fun_ 
            RESULT.Var_arg= S.Var_arg 
            RESULT.Type_obj_= S.Type_obj_
            RESULT.Is_star_operation = S.Is_star_operation
            RESULT.Is_param= S.Is_param
            RESULT.Is_const= S.Is_const
            ---------- '3'
            FOR it IN S.Items_[] :
                it = Duplicate_expr(it, Curf)
                RESULT.Items_[] << it ; 
            FOR a IN S.Assignments_[] :
                RESULT.Assignments_[] << a ;
            FOR a IN S.Before_assign_[] :
                RESULT.Before_assign_[] << a ;
            .
            
        FUN apply_S|_function(
        {Expr} E|xpression_to_str, {Parser} Parse|r_source) ==> {Expr}
        	:
			{kind_type} ek|ind_of_type = E.Type_expr.Kind
			CASE ?
			[ek == 'CLASS'] ?
				PUSH comp(Parse).Suppress_err = TRUE :
	       			 {Fun} fS|tr_function = E.Type_expr.Search_fun("Str", 
	       				ONLY_METHODS | CASE_SEN, TRUE)
				;
	       		CASE fS == NONE ?
	       		     fS = E.Type_expr.Search_fun("Str", 
	       				CASE_SEN | IMPORTED_CL, TRUE)
	       				
	       		     CASE !E.Type_expr.Is_descend(fS.Param[0].Type_, 
	       		     	  Parse.Compiler)
	       		     	  ?
	       		          fS = NONE
	       		          RESULT = E ==> ;
	       		; 
	       			
			[ek == 'STRUCTURE'] ?
			     fS = E.Type_expr.In_class_.Search_fun_by_param("Str",
			     	E.Type_expr)
			     	
	       		CASE fS == NONE ?
	       			 PUSH comp(Parse).Suppress_err = TRUE :     
		       		      fS = E.Type_expr.Search_fun("Str", 
		       				 CASE_SEN | IMPORTED_CL, TRUE)
	       			 ;
	       		;
	       		CASE fS.Param[0].Type_ != E.Type_expr ?
	       		     fS = NONE ;
			;
			CASE fS == NONE ?
				 PUSH comp(Parse).Suppress_err = TRUE :     
				      fS = comp(Parse).Current_class.Search_fun("Str",
				     	 CASE_SEN | IMPORTED_CL, TRUE)
				 ;
			     CASE ?
			     [fS.Param[0].Type_.Kind != ek] ? fS = NONE
			     [ek == 'STRUCTURE' && fS.Param[0].Type_ != E.Type_expr] ?
	       		      fS = NONE ;
			;
			CASE fS == NONE ?
			     CASE ek ?
			     ['INT']: fS = comp(Parse).SYSFUN_Str
			     ['REAL']: fS = comp(Parse).SYSFUN_RealStr
			     ['BOOL']: fS = comp(Parse).SYSFUN_BoolStr
			     ['ENUM']: fS = comp(Parse).SYSFUN_Str
			     ['STR', 'STRUCTURE', 'CLASS']: NONE ;
			;
			CASE fS == NONE ?
			 	 PUSH comp(Parse).Suppress_err = TRUE :     
			      	  fS = comp(Parse).Current_class.Find_fun("Str", TRUE)
			 	 ;
			     CASE ek == 'STRUCTURE'
			       	  && fS.Param[0].Type_ != E.Type_expr
			       	  ?
	       		      fS = NONE ; 
			;
			CASE fS == NONE ? RESULT = E ==> ;
			
			{Expr} r|esulting_expr = {Expr}(Operation= 'FUN', Fun_= fS,
				Items_[] << E), >> comp(Parse).Current_fun.All_expr[]
				
			RESULT = r . 
            
            
        METHOD Is_constant_expr ==> BOOL, RECURSIVE :
            CASE Is_const ? RESULT = TRUE ==> ;
            CASE Operation ?
            ['UNKNOWN']: NONE
            ['BINARY', 'INDEX']:
                RESULT = Arg1_.Is_constant_expr 
                RESULT &&= Arg2_.Is_constant_expr
                CASE Arg3_ != NONE ? RESULT &&= Arg3_.Is_constant_expr ; 
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN']:
				RESULT = Fun_.Modifiers['STATIC'] 
				RESULT &&= !Fun_.Modifiers['NATIVE_FUN']
				RESULT &&= all_arguments_const(Items_[]) 
				RESULT &&= !Fun_.Calling_natives
            ['VAR']: RESULT = Var_arg.Is_const
            ['FIELD', 'NEW_OBJ', 'AS']: NONE
            ['ARRAY']: RESULT = TRUE
            ['CONST']: RESULT = Localize_n == ""
            ['INT2REAL']: RESULT = Arg1_.Is_const
            ['NOT_B', 'NOT', 'NEG']: RESULT = FALSE ; .
            
            
        FUN all_arguments_const( {Expr} Arg|uments[] ) ==> BOOL :
            FOR a IN Arg[] :
                CASE !a.Is_constant_expr ? ==> ;
            ;
            RESULT = TRUE .
            
            
        METHOD remove_children_from_const_expr(
        	{Type} Class|_parent)
        	:
            CASE Arg1_.Is_constant_expr ? Arg1_.remove_from_const_expr(Class) ;
            CASE Arg2_.Is_constant_expr ? Arg1_.remove_from_const_expr(Class) ;
            CASE Arg3_.Is_constant_expr ? Arg1_.remove_from_const_expr(Class) ;
            FOR i IN Items_[] :
                CASE i.Is_constant_expr ? i.remove_from_const_expr(Class) ;
            ; .
            
        METHOD remove_from_const_expr(
        	{Type} Class|_parent)
        	:
            Class.Constant_expr[].Remove(THIS)
            Is_const = FALSE .
            
        */
        static int CNT_Recognize;

        public static Expression Recognize(Parser Parse)
        {
            if (CNT_Recognize++ == 310)
            { }

            bool save_Ending_incl = Parse.Ending_incl;
            try
            {
                List<Expression> operands = new List<Expression>();
                List<Bin> signs = new List<Bin>();
                for (int x = Parse.Pos; x <= Parse.Last(); x++)
                {
                    Expression oper = obtain_operand(Parse);
                    if (oper == null) break;
                    oper = Chain_operations(oper, Parse);
                    operands.Add(oper);
                    if (Parse.End_of_expr()) break;
                    signs.Add(Parse.Binary_op());
                }
                if (operands.Count == 0)
                {
                    Parse.Err("Waiting for Expression but: " + Parse.Next20());
                    return null;
                }
                //------------------------- operations tree'
                int Nmax = operands.Count;
                Parse.Do_priorities(new string[] { 
                    " ", "*", "+", "^", "|", "<", "I", "&&", "||" }, 
                    operands, signs);
                if (operands.Count > 2)
                    Parse.Err("Internal error: expression is not reduced");
                Expression Result = operands[0];
                if (Result.Operation == Operation_kind.BINARY)
                    Result.Type_obj_ = Result.calculate_type(Parse.Compiler_);
                return Result;
            }
            finally { Parse.Ending_incl = save_Ending_incl; }
        }

        /*
        
        METHOD calculate_type(
        	{Compiler} C|ompiler) ==> {Type}, RECURSIVE
        	:
			CASE THIS == NONE ? ==> ;
            CASE Operation == 'BINARY' ?
				 CASE Sign == 'CONCAT' ? 
				      FOR it IN Items_[] :
				          CASE it.Type_expr.Kind != 'STR' ? ==> ;
				      ;
				      RESULT = C.TYPE_STR ==> ;
			ELSE RESULT = Type_expr ==> ;
			
            CASE Arg1_.Operation == 'BINARY' ?
                Arg1_.Type_obj_ = Arg1_.calculate_type(C) ;
            CASE Arg2_.Operation == 'BINARY' ?
                Arg2_.Type_obj_ = Arg2_.calculate_type(C) ;
            CASE Sign ?
            	['UNDEFINED']: NONE
                ['AND', 'OR', 'LESS', 'LESS_OR_EQ', 'GREATER', 'GREATER_OR_EQ',
                'EQUAL', 'NOT_EQ', 'IN', 'NOT_IN', 'LIKE', 'UNLIKE']:
                    RESULT = C.TYPE_BOOL
                ['CONCAT']: RESULT = C.TYPE_STR
                ['AND_B', 'OR_B', 'XOR_B', 'REST']: RESULT = C.TYPE_INT
                ['PLUS', 'MINUS', 'MULT', 'DIV']: RESULT = Arg1_.Type_expr
                    CASE RESULT.Kind == 'INT' ? RESULT = Arg2_.Type_expr ;
            ; .
        */
        private Type calculate_type(Compiler C)
        {
            if (Operation != Operation_kind.BINARY) return Type_expr();
            if (Arg1_.Operation == Operation_kind.BINARY)
                Arg1_.Type_obj_ = Arg1_.calculate_type(C);
            if (Arg2_ != null && Arg2_.Operation == Operation_kind.BINARY)
                Arg2_.Type_obj_ = Arg2_.calculate_type(C);
            switch (Sign)
            {
                case Bin.AND: case Bin.OR: case Bin.LESS: case Bin.LESS_OR_EQ: case Bin.GREATER: case Bin.GREATER_OR_EQ:
                case Bin.EQUAL: case Bin.NOT_EQ: case Bin.IN: case Bin.NOT_IN:
                    return C.TYPE_BOOL;
                case Bin.CONCAT: return C.TYPE_STR;
                case Bin.AND_B:
                case Bin.OR_B:
                case Bin.XOR_B:
                case Bin.REST: return C.TYPE_INT;
                case Bin.PLUS: case Bin.MINUS: case Bin.MULT: case Bin.DIV:
                    Type Result = Arg1_.Type_expr();
                    if (Result.Kind == Type.Kind_type.INT)
                        Result = Arg2_ == null ? null : Arg2_.Type_expr();
                    return Result;
                default: C.Error("Internal error - forgot sign " + Bin_names[(int)Sign]);
                    return null;
            }
        }

        /*
        
        FUN Obtain_operand(
        	{Parser} Parse|_src) ==> {Expr}, NEW
        	:
        	RESULT = obtain_operand(Parse) .
        	 
        FUN obtain_operand(
        	{Parser} Parse|_src) ==> {Expr}, 
            NEW, RECURSIVE
            :
            -------------------------- 'Obtain operand in current class context'
            //DEBUG: "obtain operand >>> " Parse.Rest_of_line #NL ;
            INT pos_before = Parse.Pos 
			CASE Parse.Symbol(".") ? 
			     {Fun} cf|unction_current = comp(Parse).Current_fun
				 ------------ '.field - use Last_arg'
			     CASE Parse.End_of_line ? 
			          Parse.Err("Waiting for expression but '.' found"
			          ""._WaitExprButDot) ==> ;
			     CASE cf.Last_arg == NONE ? 
			          Parse.Err("There is no previous argument to use .field"
			          " operands"._NoLastArg) ==> ;
			     STR fname|_of_field = Parse.Ident
			     {Type} type_la|st_arg = cf.Last_arg.Type_expr
			     
			     {Var} field|_from_last_arg = type_la.Search_field(fname)
			     CASE field != NONE ?
			     	  //DEBUG: "field found: " fname #NL ;
				      {Expr} temp|orary = {Expr}(
				     	 Operation = 'FIELD', Arg1_= cf.Last_arg, Var_arg= field)
			     ELSE
			     	  {Fun} f|unction_to_call = type_la.Search_fun(
			     	  	fname, ONLY_METHODS | CASE_SEN, TRUE)
			     	  	
			     	  CASE ?
			     	  [f == NONE && cf.Last_arg.Is_array] ?
			     	      f = array_function(cf.Last_arg, Parse, fname)
		                  CASE f == comp(Parse).SYSFUN_Delete 
		                 	   || f == comp(Parse).SYSFUN_Remove
		                 	   ?
		                       cf.Is_deleting_obj = TRUE ;
			     	  [f == NONE] ?
			     	      f = scalar_function(cf.Last_arg, Parse, fname)
			     	  ;
			     	  CASE f == NONE && type_la.Kind != 'CLASS' ?
			     	       f = comp(Parse).Current_class.Search_fun(fname, 
			     	       	   ONLY_ST | CASE_SEN | IMPORTED_CL, TRUE)
			     	       	   
			     	       CASE f.Param[0].Type_ != type_la ? f = NONE ;
			     	  ;     
			     	  CASE f != NONE ?
			     	  	   Parse.Pos = pos_before     
			     	       RESULT = chain_field_or_fun(cf.Last_arg, Parse) ==>
			     	  ;
			     ;
			     CASE temp == NONE ?
				      Parse.Err("Field or function did not found"
				           ""._FieldOrFunNotFound ": " fname)
			     ;
            ELSE 
            	 temp = obtain_operand_in_c(
            		Parse, comp(Parse).Current_class) ;
            RESULT = may_be_trapping_scalar(temp, Parse) .
            
		FUN may_be_trapping_scalar|_variable_read(
			{Expr} Ex|pression_returned,
			{Parser} Parse|_of_source) ==> {Expr}, NEW
			:
			RESULT = Ex
			CASE comp(Parse).Current_fun.Modifiers['TRAP_FUN'] ?
			     ==> ;
            CASE Ex.Operation == 'FUN' && Ex.Fun_.Modifiers['TRAP_FUN'] ?
                 Parse.Err("It is not allowed to call TRAP function "
                 "directly"._ETrapDirect ": " Ex.Fun_.Whole_name)
            ;
            CASE comp(Parse).Current_fun.Left_side ? ==> ;
            CASE ?
            [!comp(Parse).Debugging && !comp(Parse).TEST_value] ? ==>
            [RESULT.Operation == 'INDEX'] ?
                 RESULT = may_be_trapping_array(RESULT, Parse) ==>
   			[RESULT.Operation !IN ['FIELD', 'VAR']] ? ==>
   			[RESULT.Var_arg.Is_array] ? ==>
   			[!RESULT.Var_arg.Modifiers['TRAP']] ? ==>
   			
   			[RESULT.Var_arg.Trap_read_ == NONE || (
   			 !comp(Parse).Debugging && !comp(Parse).TEST_value)] ? ==>
   			 
   			[comp(Parse).Current_fun.Modifiers['TRAP_FUN']] ? ==> ;
   			------------------------------------- 'call trap method'
   			{Expr} va|_variable_accessing_expression = RESULT
   			CASE RESULT.Operation == 'FIELD' ?
   			     {Expr} tthis|_for_trap = va.Arg1_
   			ELSE tthis = va.This_ ;
   			
   			RESULT = {Expr}(Operation = 'FUN',
   				Fun_ = va.Var_arg.Trap_read_, This_ = tthis,
   				Original_variable_expr_ = va)
   				
   			va.Var_arg.Trap_read_.Usage_count += 1
   			.
			
		FUN may_be_trapping_array|_variable_read(
			{Expr} Ex|pression_returned,
			{Parser} Parse|_of_source) ==> {Expr}, NEW
			:
			RESULT = Ex
			CASE comp(Parse).Current_fun.Modifiers['TRAP_FUN'] ?
				 ==> ;
			CASE ?
			[Ex.Arg1_.Operation !IN ['FIELD', 'VAR']] ? ==>
			[!Ex.Arg1_.Var_arg.Modifiers['TRAP']] ? ==>
			
			[Ex.Arg1_.Var_arg.Trap_read_ == NONE || (
   			 !comp(Parse).Debugging && !comp(Parse).TEST_value)] ? ==> ;
   			 
			CASE Ex.Arg1_.Operation == 'FIELD' ?
			     {Expr} tthis|_for_trap = Ex.Arg1_.Arg1_
			ELSE tthis = Ex.Arg1_.This_ ;
			
			RESULT = {Expr}(Operation = 'FUN',
				Fun_ = Ex.Arg1_.Var_arg.Trap_read_, This_ = tthis,
				Items_[] << Ex.Arg2_,
				Original_variable_expr_ = Ex)
				
			Ex.Arg1_.Var_arg.Trap_read_.Usage_count += 1
			.
			
		FUN comp|iler_from_parser(
		{Parser} P|arser_in) ==> {Compiler}
		    :
			RESULT = P.Compiler_.{Compiler} .
			
		FUN brackets_to_wait(
		{Parser} Parse|_of_text) ==> INT
		    :
		    Parse.Skip_sp
			CASE Parse.Prev_char != "(" ? ==> ;
		    CASE Parse.Symbol("[") ? 
    	         FOR k IN [1 TO 100_000] :
    	             RESULT = k
    	             CASE Parse.Symbol("[") ? CONTINUE k
    	             ELSE ==> ;     
    	         ;
    	    ; .
			
        FUN obtain_operand_in_c|ontext_of_class(
        	{Parser} Parse|_src,
            {Type} C|lass_context) ==> {Expr}, NEW, RECURSIVE
            :
        {Fun} cfun|ction_current = comp(Parse).Current_fun 
        PUSH cfun.Level_operand = cfun.Level_operand + 1 :
            ------------------------------ 'Look at the first character'
            Parse.Skip_sp
            INT pos|ition_start = Parse.Pos
            CASE Parse.Next_char ?
            ["("]: Parse.Skip_char
            	   INT k|ount_brackets_waiting = brackets_to_wait(Parse)
            	   ------------------------- 'recognize (subexpression)'
                   RESULT = Recognize(Parse)
                   FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                   Parse.Wait(")") ==>
            ["-"]: Parse.Skip_char
            
                   RESULT = obtain_operand(Parse), 
                   >> comp(Parse).Current_fun.All_expr[]
                          
                   RESULT = RESULT.Chain_operations(Parse, FALSE),
                   >> comp(Parse).Current_fun.All_expr[]
                   		  
                   CASE ?
                   [RESULT.Type_expr.Kind IN ['CLASS', 'STRUCTURE']] ?
                        {Fun} operator 
                   = comp(Parse).Current_fun.Search_operator(
                        'MINUS', RESULT, NONE)
                        
                        CASE operator != NONE ?
                             operator.Count_ref += 1
                             operator.Usage_count += 1
                         	 comp(Parse).Current_fun.Calls_fun(operator)
                             {Expr} arg|ument = RESULT
                             arg.Is_param = TRUE
                         	 comp(Parse).Current_fun.All_expr[] << arg
                             ------------- 'operator -x'
                             RESULT = {Expr}(Operation = 'FUN',
                             	Fun_ = operator, Items_[] << arg),
                        		>> comp(Parse).Current_fun.All_expr[] ==>
                        		
                        ELSE BOOL bad_not_app|licable = TRUE
                        ;
                   [RESULT.Type_expr.Kind !IN ['INT', 'REAL']] ?
                        bad_not_app = TRUE ;
                   CASE bad_not_app ?
                        PUSH Parse.Pos = pos :
                            Parse.Err("Operation '-' is not "
                            "applicable to"._Eoper 
                            " " RESULT.Type_expr.Kind.Name 
                            ": " Parse.Next20) ;
                   ;
                   {Expr} neg|ate_operand = RESULT 
               
                   RESULT = {Expr}(Operation = 'NEG', Arg1_ = neg),
                   >> comp(Parse).Current_fun.All_expr[] ==>
                   
            ["+"]: Parse.Skip_char
            
                   RESULT = obtain_operand(Parse), 
                   >> comp(Parse).Current_fun.All_expr[]
                          
                   RESULT = RESULT.Chain_operations(Parse, FALSE)
                   CASE RESULT.Type_expr.Kind !IN ['INT', 'REAL'] ?
                        PUSH Parse.Pos = pos :
                            Parse.Err("Operation '+' is not "
                            "applicable"._Eoper2 ": " Parse.Next20) ;
                   ;
                   ==>
            ["!"]: Parse.Skip_char
            	   PUSH cfun.Count_not = cfun.Count_not + 1 :
	                    RESULT = obtain_operand(Parse),
	                    >> comp(Parse).Current_fun.All_expr[]
	                           
	                    RESULT = RESULT.Chain_operations(Parse, FALSE),
	                    >> comp(Parse).Current_fun.All_expr[]
	                    
	                    CASE RESULT.Type_expr != NONE && (
	                         RESULT.Type_expr.Kind == 'BOOL')
	                         ?
	                         {Expr} a1|rgument_to_not = RESULT
	                         
	                         RESULT = {Expr}(Operation = 'NOT', Arg1_ = a1),
	                         >> comp(Parse).Current_fun.All_expr[]
	                    ELSE 
	                         PUSH Parse.Pos = pos :
	                              Parse.Err("Operation '!' is "
	                              "not applicable"._Eoper3 
	                              ": " Parse.Next20) ;
	                    ;
            	   ;
                   ==>
            ["~"]: Parse.Skip_char
            
                   RESULT = obtain_operand(Parse),
                   >> comp(Parse).Current_fun.All_expr[]
                          
                   RESULT = RESULT.Chain_operations(Parse, FALSE),
                   >> comp(Parse).Current_fun.All_expr[]
                   
                   CASE RESULT.Type_expr.Kind == 'INT' ?
                        comp(Parse).Current_class.Detect('BITWISE')
                   ELSE 
                        PUSH Parse.Pos = pos :
                             Parse.Err("Operation '~' is "
                             "not applicable"._Eoper4 ": " Parse.Next20) ;
                   ;
                   a1 = RESULT
                   
                   RESULT = {Expr}(Operation = 'NOT_B', Arg1_ = a1),
                   >> comp(Parse).Current_fun.All_expr[] ==>
                   
            ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]:
                   RESULT = obtain_num_const(Parse) ==>
            [#QU, "#", "@"]:
                   RESULT = {Expr}(Operation = 'CONST',
                        At_line = Parse.Line, At_pos = Parse.Pos,
                        Var_arg = {Var}(Is_const = TRUE, Line = Parse.Line,
                            Type_ = comp(Parse).TYPE_STR,
                            Str_c = Parse.String_const(FALSE))) ==>
                            
            ["'"]: RESULT = obtain_enum_item(Parse,
                            comp(Parse).Enumeration_wait) ==>
                            
            ["{"]: STR nt|ype_name = Parse.Scan_type
                   {Type} t|ype_specified = C.Find_type(nt)
                   comp(Parse).Current_class.Can_be_imported(t, nt)
                   CASE t.Kind IN ['CLASS'] && (
                        C != comp(Parse).Current_class)
                        ?
                        Parse.Wait(".")
                        BOOL class_spec|ified = TRUE
                        RESULT = obtain_operand_in_c(Parse, t) ==> ;
                        
                   CASE nt IN C.Structure_fields_need_q[]
                   		&& C == comp(Parse).Current_class 
                   		&& !class_spec 
                   		&& "}.{" !IN nt
                        ?
                        Parse.Err("Enumeration"._Eenum " " nt 
                        " " ("is defined in several classes, so it must be "
                        "qualified"._Eis )) ;
                        
                   Parse.Skip_sp
                   CASE Parse.Next_char == "." ?
                        INT was_pos|ition = Parse.Pos
                        Parse.Skip_char
                        CASE Parse.End_of_line ?
                             Parse.Pos = was_pos
                             RESULT = Obtain_new(Parse, t, FALSE) ==>
                        ;
                        Parse.Skip_sp
                        CASE Parse.Next_char == "'" ?
                             RESULT = obtain_enum_item(Parse, t) ==> ;
                        was_pos = Parse.Pos
                        ------------------------ 'qualified constant'
                        {Var} fconst|ant_found = t.Search_const(
                        	Parse.Ident, FALSE)
                        	
                        CASE fconst != NONE ?
                             RESULT = {Expr}(Operation = 'CONST',
                             	Var_arg = fconst),
                        >> comp(Parse).Current_fun.All_expr[]
                             ==> ;
                        ------------------- 'no, only static function'
                        Parse.Pos = was_pos
                        RESULT = obtain_static_fun(Parse, t) ==>
                   ELSE RESULT = Obtain_new(Parse, t, FALSE) ==> ;
            ["["]: RESULT = obtain_array(Parse) ==>
            ["*"]: RESULT = obtain_index_last(Parse) ==> 
            ["$"]: Parse.Skip_char
                   STR name_def|ine = "$" Parse.Ident
                   INT def|ine_index INDEXING STR
                   def = comp(Parse).Defined_name[].Find(name_def)
                   CASE def < 0 ?
                        Parse.Warn("Variable"._Wvar " " name_def 
                        " " ("is not defined"._Wisnot ) )
                   ;
                   RESULT = New_str(Parse, comp(Parse).Defined_value[def]) ==>
            ;
            ---------------------------------------- 'identifier'
            STR id|entifier = Parse.Ident
            ------------------------------------- 'localization of a string?'
            CASE id.[0] == "_" ? 
	             CASE id.Len > 1 && id.[1] != "_" ?
	                  Parse.Wait("(")
	                  k = brackets_to_wait(Parse)
	                  RESULT = Recognize_typed(Parse, 'STR')
	                  FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
	                  Parse.Wait(")")
	                  make_localizable(RESULT, id.[1 TO *], Parse) ==> ;
	             CASE id == "_" ? 
	             	  -------- 'replacement for the variable left to the ='     
	             	  CASE cfun.Assign_target == NONE ? 
	             	       Parse.Err("Using _ to refer to the left side of "
	             	       "an assignment statement is not appropriate here"
	             	       ""._E_NotAppropriate) ;
	                  RESULT = cfun.Assign_target
	                  CASE RESULT.Is_array ? 
	                       Parse.Wait("[")
	                       CASE Parse.Symbol("]") ? ==> ;
	                       
	                       PUSH comp(Parse).Current_array = cfun.Assign_target :
		                        {Expr} v_index|_value = Recognize_typed(
		                        	 Parse, 'INT'),
		                       		 >> cfun.All_expr[]   
		                       		 
		                        BOOL a_range|_of_array = Parse.Symbol("TO")
		                             
		                        {Expr} e_index|_ending
		                        CASE a_range ?
		                             e_index = Recognize_typed(Parse, 'INT'),
		                             >> cfun.All_expr[]
		                        ELSE e_index = NONE ;
	                       ;
	                       
	                       RESULT = {Expr}(Operation= 'INDEX', 
	                       		Arg1_= cfun.Assign_target,
	                       		Arg2_= v_index, Arg3_= e_index),
	                       		OWNED BY cfun
	                       		
	                       Parse.Wait("]") ;
	                  ==> ;
            ;
			---------------------------------------- 'SQL queries'
			CASE (cfun.Appending_to_DB) 
			     && id IN ["SELECT", "INSERT", "UPDATE", "DELETE"] 
			     ?
				 RESULT = Recognize_SQL(id, Parse) ==> ;
            ---------------------------------------- 'Variable ?'
            BOOL is_BASE|_identifier = id == "BASE"
            CASE !is_BASE && cfun != NONE ?
                 {Var} v|ariable = cfun.Search_var(id, !Parse.Case_insensitive)
            ;
            CASE v != NONE ?
                 CASE v.Is_array && !Parse.Next_symbol("[") &&
                 	  ! Parse.Allow_omit_array_brackets
                 	  ?
                      Parse.Err("Using array without []"._EusingArr) ;
            	 CASE comp(Parse).Current_fun.Left_side && (
            		  cfun.Level_operand == 1)
            		  ?
            	      v.Used_for_w = TRUE
            	 ELSE v.Used_for_r = TRUE ;
                 v.Count_ref += 1
                 v.Provide_traps
                 ---------- 'check if accessing v is applicable'
                 CASE v.Declared_in_debug && !(
                      comp(Parse).Current_fun.Compiling_debug)
                      ?
                      Parse.Err("Variable"._Evar 
                      " " v.Whole_name " " ("was declared in debug "
                      "block and can not be used in regular code"._Ewas ))
                 ;
                 CASE v.Modifiers['ABANDONED_FIELD'] ?
                      Parse.Err("Field"._Efield " " v.Whole_name 
                      " " ("is abandoned, use"._Eis2 ) ": " v.Deprecate)
                 ;
                 CASE v.Modifiers['DEPRECATED_FIELD'] ?
                      Parse.Warn("Field"._Wfield " " v.Whole_name 
                      " " ("is deprecated, use"._Wis ) ": " v.Deprecate)
                 ;
                 CASE v.Final_name == "this" ? cfun.This_used = TRUE ;
                 CASE !cfun.Modifiers['STATIC'] && (
                      v !IN comp(Parse).Current_fun.Local_var[])
                      ?
                      cfun.This_used = TRUE ;
                 CASE v.Is_loop && v.For_.Array==NONE ?
                      CASE cfun.Left_side && !Parse.Next_symbol(".") ?
                           Parse.Err("Assigning value to a loop "
                           "variable"._Eassign ": " v.Whole_name)
                      ;
                      CASE v.Modifiers[{var_mod}.'READ'] ?
                           Parse.Err(
                           "Assigning value to a read only variable"._Eassign2 )
                      ;
                      CASE loop_variable_is_out(Parse, v) ?
                           Parse.Err("Using loop variable out of a loop"._Eusing
                           ": " v.Names[*]) ;
                 ;
                 CASE v.In_type_ == NONE ?
                      -------------------- 'local var'
                      {Expr} loc|al_variable = {Expr}(Operation = 'VAR', 
                      		 Var_arg = v, At_line = Parse.Line, At_pos = pos),
                      		 OWNED BY Parse
                      		 
                      CASE v.Is_loop && v.For_.In_struct_array != NONE ?
			               RESULT = {Expr}(Operation= 'INDEX',
			                    Arg1_= v.For_.In_struct_array,
			                    Arg2_= loc, For_loop_var= TRUE),
			                    OWNED BY Parse ==> 
			          ;
	                  RESULT = loc ==>
                 ;
	                  
                 {Expr} this_of_class|_which_method_is = {Expr}(
                 	    Operation = 'VAR',
                 	    Var_arg = comp(Parse).THIS_var,
                 	    Type_obj_=comp(Parse).Current_fun.Class),
                 	    OWNED BY Parse
                 	    
                 RESULT = {Expr}(Operation = 'FIELD', Var_arg = v, 
                 	At_line = Parse.Line, At_pos = pos,
                 	Arg1_ = this_of_class),
                 	OWNED BY Parse ==> ;
            ----------------------------------------------- 'Function ?'
            CASE is_BASE ?
                 cfun.Calls_base = TRUE
                 {Fun} f|unction_ancestor = cfun.Ancestor_
                 CASE f == NONE ? 
                      Parse.Err("BASE is not applicable: there is no base "
                      "method for"._Ebase " " cfun.Whole_name )
                 ;
                 CASE cfun == comp(Parse).Current_class.Construct 
                 	  || cfun 
                 	  	 == comp(Parse).Current_class.Destruct
                      ?
                      Parse.Err(
                      "Direct call of base CONSTRUCT or DESTRUCT"
                      ""._Edirect )
                 ;
            ELSE
            	 CASE f == NONE && comp(Parse).Current_class != NONE ?
            	      INT flags|_search = IMPORTED_CL //| ONLY_ST
            	      CASE !Parse.Case_insensitive ? flags |= CASE_SEN ;
            	      
            	 	  f = comp(Parse).Current_class.Search_fun(
            	 	  	  id, flags, TRUE) ;
            ;
            CASE f != NONE ?
                 CASE f.Modifiers['POP'] && (
                      !comp(Parse).Current_fun.Compiling_push)
                      ?
                      Parse.Err("Calling function having modifier POP not in "
                      "a PUSH statement header"._Ecall )
                 ;
                 CASE f.Modifiers['POP'] ?
                      Parse.Err("Direct call of a POP-method"._Edir 
                      " " f.Whole_name)
                 ;
                 CASE ! f.Modifiers['STATIC'] && cfun.Modifiers['STATIC'] ?
                     Parse.Err("Calling non-static method from static function"
                     " without object implicit parameter"._Ecall2 
                     ": " f.Class.Whole_name "." f.Whole_name)
                 ;
                 CASE ! f.Modifiers['STATIC'] ?
                      RESULT = Operation_call_fun(
                      		   f, comp(Parse).THIS_expr, Parse)
                      CASE is_BASE ? RESULT.Operation = 'BASE_FUN' ;
                      comp(Parse).Current_fun.This_used = TRUE
                      ==>
                 ELSE RESULT = Operation_call_fun(f, NONE, Parse) ==> ;
            ;
            ----------------------------------------------- 'Constant ?'
            RESULT = system_const(id, Parse, pos),
            		 >> comp(Parse).Current_fun.All_expr[]
            		 
            CASE RESULT != NONE ? ==> ;
            v = C.Search_const(id, TRUE)
            CASE v != NONE ?
                RESULT = {Expr}(Operation = 'CONST', Var_arg = v,
                    At_line = Parse.Line, At_pos = pos) ==> ;
            ------------ 'sytem_fun(expr[,...])'
            RESULT = System_function_traditional(id, Parse, pos)
            CASE RESULT != NONE ? ==> ;
            ------------------------------------------------- 'Not found'
            STR similar|_names[]
            comp(Parse).Current_fun.Find_similar(id, similar[])
            C.Find_similar(id, similar[], TRUE)
            CASE similar[].Count > 0 ? 
                 FOR s IN similar[] : STR list_sim|ilar = list_sim "," s ;
            
                 Parse.Err("Name not found"._EnameNotFound ": " id
                 ". May be you mean one of others ("._MayBeOther 
                 "" list_sim.[1 TO *] ") ?") 
            ELSE
	             Parse.Err("Name not defined"._Ename ": " id
	             " (May be it is necessary to refine a context?)") 
            ;
       	; .
        
        FUNCTION system_const(
        STR id|entifier, {Parser} Parse|_of_source, INT pos|ition_where) 
        ==> {Expr}, NEW	
        	:
            CASE id ?
                ["NONE"]: {Var} c|onstant_ref = comp(Parse).NONE_c    
                //["TRUE"]: c = comp(Parse).TRUE_c
                //["FALSE"]: c = comp(Parse).FALSE_c
                ["INF", "INFINITY"]: c = comp(Parse).INFINITY_c
                ["NAN"]: c = comp(Parse).NAN_c
                            
                ["TEST"]:   RESULT = {Expr}(Operation = 'FUN',
                            Fun_ = comp(Parse).TEST_f,
                            At_line = Parse.Line, At_pos = pos),
                            >> comp(Parse).Current_fun.All_expr[] ==> 
            ;
            CASE c != NONE ? RESULT = {Expr}(Operation = 'CONST', Var_arg = c,
                            At_line = Parse.Line, At_pos = pos) ; .
        
        FUNCTION System_function_traditional|_call(
        STR Id|entifier, {Parser} Parse|_of_source, INT Pos|ition_where)
        ==> {Expr}, NEW
        	:
	        INT was_pos|ition = Parse.Pos
            CASE ?
            [Id.Upper IN ["COUNT", "CLEAR", "LEN","LENGTH", "NAME", "INDEX",
             "STR", "STRING", "INT", "INTEGER", "NEXT", "PREV", "PREVIOUS",
             "FIRST", "LAST", "CLONE", "DISMISS"] && Parse.Symbol("(")] ?
                 INT k|ount_bracketsto_wait = brackets_to_wait(Parse)
                 {Expr} v|ariable_parameter = Recognize(Parse),
                 		>> comp(Parse).Current_fun.All_expr[]
                 		
                 FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait(")")
                 BOOL ok|_parameters_applicable = !v.Is_array
                 CASE Id.Upper ?
                 ["COUNT"]: {Fun} f|unction_system = comp(Parse).SYSFUN_Count
                 			ok  = v.Is_array
                 ["CLEAR"]: f = comp(Parse).SYSFUN_Clear
                 			ok = v.Is_array
                 ["LEN", "LENGTH"]: f = comp(Parse).SYSFUN_Len
                 					ok &&= v.Type_expr.Kind == 'STR'
                 ["NAME"]: f = comp(Parse).SYSFUN_Name
                 		   ok &&= v.Type_expr.Kind == 'ENUM'
                 ["INDEX"]: f = comp(Parse).SYSFUN_Count
                 			ok &&= v.Var_arg.Is_loop
                 ["STR", "STRING"]:
                 	CASE ?
                 	[v.Type_expr.Kind == 'BOOL'] ?
                 	     f = comp(Parse).SYSFUN_BoolStr
                 	[v.Type_expr.Kind == 'REAL'] ?
                 	     f = comp(Parse).SYSFUN_RealStr
                 	[v.Type_expr.Kind == 'INT'] ?
                 	     f = comp(Parse).SYSFUN_Str
                 	     
                 	ELSE Parse.Err("Function STRING() is not applicable to "
                 		 "the type"._EStrNotApplicable
                 		 ": " v.Type_expr.Kind.Name)
                 	;
                 ["INT", "INTEGER"]:
                 	CASE ?
                 	[v.Type_expr.Kind == 'REAL'] ?
                 	     f = comp(Parse).SYSFUN_RealInt
                 	[v.Type_expr.Kind == 'ENUM'] ?
                 	     f = comp(Parse).SYSFUN_EnumInt
                 	[v.Type_expr.Kind == 'STR'] ?
                 	     f = comp(Parse).SYSFUN_StrInt

                 	ELSE Parse.Err("Function INTEGER() is not applicable to "
                 		 "the type"._EIntNotApplicable 
                 		 ": " v.Type_expr.Kind.Name)
                 	;
                 ["NEXT"]: f = comp(Parse).SYSFUN_Next
                 		   ok &&= v.Type_expr.Kind == 'ENUM'
                 ["PREV", "PREVIOUS"]: f = comp(Parse).SYSFUN_Previous
                 ["FIRST"]: f = comp(Parse).SYSFUN_First
                 		    ok &&= v.Type_expr.Kind == 'ENUM'
                 ["LAST"]: f = comp(Parse).SYSFUN_Last
                 		   ok &&= v.Type_expr.Kind == 'ENUM'
                 ["CLONE"]: f = comp(Parse).SYSFUN_Clone
                 		    ok &&= v.Type_expr.Kind == 'STRUCTURE'
                 ["DISMISS"]: f = comp(Parse).SYSFUN_Dismiss
                 		      ok &&= v.Type_expr.Kind == 'STRUCTURE'
                 ;
                 {Expr} temp|_result = {Expr}(Operation = 'FUN', Fun_ = f,
                 		At_line = Parse.Line, At_pos = Pos,
                 		Items_[] << v),
                 		>> comp(Parse).Current_fun.All_expr[]
                 		
            [Id.Upper IN ["FIND", "INSERT", "ALLOCATE", 
             "CLEAR", "DELETE", "REMOVE", 
             "HEX", "HEXADECIMAL", "SHIFTL", "SHIFT_LEFT", "SHIFTLEFT",
             "SHIFTR", "SHIFT_RIGHT", "SHIFTRIGHT", "ROTATEL", "ROTATE_LEFT",
             "ROTATELEFT", "ROTATER", "ROTATE_RIGHT", "ROTATERIGHT"]
             && Parse.Symbol("(")] ?
                 k = brackets_to_wait(Parse)
                 v = Recognize(Parse), >> comp(Parse).Current_fun.All_expr[]
                 ----------------- 'read additional parameter'
                 Parse.Wait(",")
                 	   
                 {Expr} p|arameter2 = Recognize(Parse),
                 	   >> comp(Parse).Current_fun.All_expr[]
                 	   
                 FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait(")")
             	 ------------------------ 'check if array complient'
                 CASE Id.Upper IN ["FIND", "INSERT", "ALLOCATE", "DELETE",
                 	  "REMOVE"]
                 	  ?
                 	  CASE v.Type_expr.Kind == 'CLASS' 
                 	  	   && Id.Upper IN ["DELETE", "REMOVE"]
                 	  	   ?
                 	       comp(Parse).Current_fun.Is_deleting_obj = TRUE
                 	  ;
                      ok = v.Is_array
                 ELSE ok = !v.Is_array ; 
                 ok &&= !p.Is_array
                 ------------------------ 'check types compatibility'
                 ok &&= p.Type_expr.Kind == 'INT'
                 {Type} t1|_xtype_of_v = v.Type_expr
                 {Type} t2|_type_of_p = p.Type_expr
                  	  
                 CASE Id.Upper ?
                 ["CLEAR"]: f = comp(Parse).SYSFUN_Clear
                 			ok = v.Is_array 
                 			v.Var_arg.Has_changing_size = TRUE
                 ["FIND"]:
                     CASE v.Is_array ?
                  	    f = comp(Parse).SYSFUN_Find_item
                  	    
                  	    ok = p.Type_expr.Kind == v.Type_expr.Kind
                  	     	   || p.Type_expr.Kind IN ['INT']
                  	     	   && v.Type_expr.Kind IN ['REAL', 'INT']
                  	     	   
                  	    ok ||= v.Type_expr.Kind != 'ENUM' 
                  	       || v.Type_expr == p.Type_expr
                  	       
                  	    ok &&= !p.Is_array
                  	    
                     ELSE f = comp(Parse).SYSFUN_Find_str
                     
                  		ok = !v.Is_array && !p.Is_array 
                  		 	 && v.Type_expr.Kind == 'STR'
                  		 	 && p.Type_expr.Kind == 'STR'
                     ;
                     
                 ["INSERT"]: f = comp(Parse).SYSFUN_Insert
                  			 ok = v.Is_array 
                  			 ok &&= !p.Is_array
                  			 
                  			 ok &&= t2.Kind == t1.Kind
                  			 	|| t1.Kind IN ['INT', 'REAL']
                  			  	&& t2.Kind == 'INT'
                  			  	
                  			 ok &&= t1.Kind != 'ENUM' || t1 == t2
                  			 
                  			 v.Var_arg.Has_changing_size = TRUE
                  			  	
                 ["REMOVE"]: f = comp(Parse).SYSFUN_Remove
                  			 ok = v.Is_array 
                  			 ok &&= !p.Is_array
                  			 
                  			 ok &&= t2.Kind == t1.Kind
                  			  	|| t1.Kind IN ['INT', 'REAL']
                  			  	&& t2.Kind == 'INT'
                  			  	
                  			 ok &&= t1.Kind != 'ENUM' || t1 == t2 
                  			 
                  			 v.Var_arg.Has_changing_size = TRUE
                     
                 ["ALLOCATE"]: f = comp(Parse).SYSFUN_Allocate
                 			   v.Var_arg.Has_changing_size = TRUE
                 ["DELETE"]: f = comp(Parse).SYSFUN_Delete
                 			 v.Var_arg.Has_changing_size = TRUE
                 ["HEX", "HEXADECIMAL"]: f = comp(Parse).SYSFUN_StrHex16
                 ["SHIFTL", "SHIFT_LEFT", "SHIFTLEFT"]:
                            f = comp(Parse).SYSFUN_Shl
                 ["SHIFTR", "SHIFT_RIGHT", "SHIFTRIGHT"]:
                            f = comp(Parse).SYSFUN_Shr
                 ["ROTATEL", "ROTATE_LEFT", "ROTATELEFT"]:
                            f = comp(Parse).SYSFUN_Rol
                 ["ROTATER", "ROTATE_RIGHT", "ROTATERIGHT"]:
                            f = comp(Parse).SYSFUN_Ror
                 ;
                 temp = {Expr}(Operation = 'FUN', Fun_ = f,
                 		At_line = Parse.Line, At_pos = Pos,
                 		Items_[] << v << p),
                 		>> comp(Parse).Current_fun.All_expr[]
                 		
            [Id.Upper == "SWAP" && Parse.Symbol("(")] ?
                 k = brackets_to_wait(Parse)
				 v = Recognize(Parse), >> comp(Parse).Current_fun.All_expr[]
				 ------------------ 'SWAP: read more 2 parameters'
                 Parse.Wait(",")
                 p = Recognize(Parse), >> comp(Parse).Current_fun.All_expr[]
                 Parse.Wait(",")
                 
                 {Expr} p3|arameter3 = Recognize(Parse), 
                 		>> comp(Parse).Current_fun.All_expr[]
                 		 
                 FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait(")")
                 
                 ------------------- 'SWAP : check parameters compatibility'
                 t2 = p.Type_expr
                 {Type} t3|_type_of_p = p3.Type_expr
                 ------------------- 'check if operation is applicable'
                 ok = v.Is_array 
                 ok &&= !p.Is_array 
                 ok &&= !p3.Is_array
                 ok &&= t2.Kind == 'INT'
                 ok &&= t3.Kind == 'INT'
                  	                
                 temp = {Expr}(Operation = 'FUN', Fun_ = f,
                 		At_line = Parse.Line, At_pos = Pos,
                 		Items_[] << v << p << p3)
            ;
            CASE temp != NONE && !ok ?
                 temp = NONE
                 Parse.Pos = was_pos
                      //Parse.Err("Function is not applicable"._E_NotAppolicable
                      //": " Id)
            ; 
            RESULT = temp .
    

        FUN loop_variable_is_out|_of_loop(
        	{Parser} Parse|_in_context,
            {Var} V|ariable_to_check) ==> BOOL
            :
            --------------------- 'check V is not used in FOR statements above'
            FOR n IN comp(Parse).Current_fun.Nesting[] :
                CASE V == n.{For}.Var ? ==> ;
            ;
            RESULT = TRUE .
            
        */
        static int CNT_obtain_operand;

        private static Expression obtain_operand(Parser Parse)
        {
            if (++CNT_obtain_operand == 18)
            { }
            return obtain_operand_in_c(Parse, Parse.Compiler_.Current_class);
        }

        private static Expression obtain_operand_in_c(Parser Parse, Type C)
        {
            Parse.Skip_sp();
            int pos = Parse.Pos;
            switch ((Parse.Next_char() + (char)0)[0])
            {
                case '(': Parse.Skip_char();
                    Expression Result = Recognize(Parse);
                    Parse.Wait(")");
                    return Result;
                case '-': Parse.Skip_char();
                    Result = obtain_operand(Parse);
                    Result = Chain_operations(Result, Parse);
                    if (Result.Type_expr().Kind != Type.Kind_type.INT &&
                        Result.Type_expr().Kind != Type.Kind_type.REAL)
                    {
                        int temp_pos = Parse.Pos;
                        Parse.Pos = pos;
                        try
                        {
                            Parse.Err("Operation '-' is not " +
                                "applicable: " + Parse.Next20());
                        }
                        finally { Parse.Pos = temp_pos; }
                    }
                    Result.Neg = true;
                    return Result;
                case '!': Parse.Skip_char();
                    Result = obtain_operand(Parse);
                    Result = Chain_operations(Result, Parse);
                    if (Result != null && Result.Type_expr() != null)
                    {
                        Type Result_type = Result.Type_expr();
                        switch (Result_type.Kind)
                        {
                            case Type.Kind_type.BOOL: break;
                            case Type.Kind_type.INT: 
                                Parse.Compiler_.Current_class.Detect(Type.Class_mod.BITWISE);
                                break;
                            default:
                                int temp = Parse.Pos;
                                Parse.Pos = pos;
                                try
                                {
                                    Parse.Err("Operation '!' is " +
                                        "not applicable: " + Parse.Next20());
                                }
                                finally { Parse.Pos = temp; }
                                break;
                        }
                        Result.Not = true;
                    }
                    return Result;
                case '0': case '1': case '2': case '3': case '4': case '5':
                case '6': case '7': case '8': case '9':
                    return obtain_num_const(Parse);
                case '\"': case '#': case '@':
                    Result = new Expression();
                    Result.Operation = Operation_kind.CONST;
                    Result.At_line = Parse.Line;
                    Result.At_pos = Parse.Pos;
                    Result.Var_arg = new Variable(Parse.Compiler_);
                    Result.Var_arg.Is_constant = true;
                    Result.Var_arg.Line = Parse.Line;
                    Result.Var_arg.Type_ = Parse.Compiler_.TYPE_STR;
                    Result.Var_arg.Str_c = Parse.String_const(false);
                    return Result;
                case '\'': return obtain_enum_item(Parse, null);
                case '{': string t = Parse.Scan_type();
                    Type T = C.Find_type(t);
                    Parse.Skip_sp();
                    switch ((Parse.Next_char() + " ")[0])
                    {
                        case '.': Parse.Skip_char();
                            Parse.Skip_sp();
                            if (Parse.Next_char() == "'")
                                return obtain_enum_item(Parse, T);
                            return obtain_static_fun(Parse, T);
                        default: return Obtain_new_obj(Parse, T, false);
                    }
                case '[': return obtain_array(Parse);
                case '*': return obtain_index_last(Parse);
            }
            //-------------------------------------- 'var/const/fun'
            string id = Parse.Ident();
            Variable v = Parse.Compiler_.Current_fun != null ? Parse.Compiler_.Current_fun.Search_var(id) : null;
            if (v != null)
            {
                v.Used = true;
                Expression Result = new Expression();
                Result.Operation = Operation_kind.VAR;
                Result.Var_arg = v;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            Function f = Parse.Compiler_.Current_class.Search_fun(id, false);
            if (f != null)
            {
                if (!f.Modifiers[(int)Function.Fun_mod.STATIC] &&
                    Parse.Compiler_.Current_fun.Modifiers[(int)Function.Fun_mod.STATIC])
                    Parse.Err("Calling non-static method from static function " +
                        "without object implicit parameter");
                return Operation_call_fun(f, Parse.Compiler_.THIS_expr, Parse);
            }
            if (id == "NONE")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.NONE_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            else if (id == "TRUE")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.TRUE_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            else if (id == "FALSE")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.FALSE_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            else if (id == "TEST")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.TEST_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            else if (id == "INF" || id == "INFINITY")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.INF_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            else if (id == "NAN")
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = Parse.Compiler_.NAN_c;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            v = C.Search_const(id);
            if (v != null)
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = v;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            Parse.Err("Name is not defined: " + id);
            return null;
        }

        /*
        
        FUNCTION obtain_num_const|ant(
        {Parser} Parse|_src) ==> {Expr}, 
            NEW
            :
            ------------------------------ 'Integer part'
            INT pos|ition_start = Parse.Pos
            
            RESULT = {Expr}(Operation = 'CONST',
                At_line = Parse.Line, At_pos = pos,
                Var_arg = {Var}(Is_const = TRUE, Line = Parse.Line,
                    Type_ = comp(Parse).TYPE_INT,
                    Int_c = Parse.Integer))
                
            STR s|tring_scanned = Parse.Source[Parse.Line].[pos TO Parse.Pos-1]
            s = s.Lower
            CASE "0x" IN s || "0o" IN s || "0b" IN s ?
                 RESULT.Var_arg.Constant_value= " " Replace_all(s.Trim, "_", "") 
                 ==> ;
            ------------------------------ 'Look at the next character'
            CASE Parse.Next_char ?
                ["."]:
                	INT bef|ore_dot = Parse.Pos
					Parse.Skip_char
					CASE Parse.Next_char !IN "0123456789" ?
					     Parse.Pos = bef ==> ;
					----------------------------- 'rescan as real'
                    Parse.Pos = pos
                    RESULT.Var_arg.Type_ = comp(Parse).TYPE_REAL
                    RESULT.Var_arg.Real_c = Parse.Real_number
                ["e", "E"]:
                	//LIKE ........................ 'rescan as real'
                    Parse.Pos = pos
                    RESULT.Var_arg.Type_ = comp(Parse).TYPE_REAL
                    RESULT.Var_arg.Real_c = Parse.Real_number
                ["x", "X"]:
                    CASE RESULT.Var_arg.Int_c != 0 ? ==> ;
                    Parse.Skip_char
                    RESULT.Var_arg.Int_c = Parse.Radix_number(16)
                ["b", "B"]:
                    CASE RESULT.Var_arg.Int_c != 0 ? ==> ;
                    Parse.Skip_char
                    RESULT.Var_arg.Int_c = Parse.Radix_number(2)
                ["o", "O"]:
                    CASE RESULT.Var_arg.Int_c != 0 ? ==> ;
                    Parse.Skip_char
                    RESULT.Var_arg.Int_c = Parse.Radix_number(8) ; .
        */
        private static Expression obtain_num_const(Parser Parse)
        {
            int pos = Parse.Pos;
            Expression Result = new Expression();
            Result.Operation = Operation_kind.CONST;
            Result.At_line = Parse.Line;
            Result.At_pos = pos;
            Result.Var_arg = new Variable(Parse.Compiler_);
            Result.Var_arg.Is_constant = true;
            Result.Var_arg.Line = Parse.Line;
            Result.Var_arg.Type_ = Parse.Compiler_.TYPE_INT;
            Result.Var_arg.Int_c = Parse.Number();
            switch ((Parse.Next_char() + " ")[0])
            {
                case '.': case 'e': case 'E':
                    Parse.Pos = pos;
                    Result.Var_arg.Type_ = Parse.Compiler_.TYPE_REAL;
                    Result.Var_arg.Real_c = Parse.Real_number();
                    break;
                case 'x': case 'X':
                    if (Result.Var_arg.Int_c != 0) return Result;
                    Parse.Skip_char();
                    Result.Var_arg.Int_c = Parse.Radix_number(16);
                    break;
                case 'b': case 'B':
                    if (Result.Var_arg.Int_c != 0) return Result;
                    Parse.Skip_char();
                    Result.Var_arg.Int_c = Parse.Radix_number(2);
                    break;
                case 'o': case 'O':
                    if (Result.Var_arg.Int_c != 0) return Result;
                    Parse.Skip_char();
                    Result.Var_arg.Int_c = Parse.Radix_number(8);
                    break;
            }
            return Result;
        }

        /*
        
        FUNCTION obtain_enum_item({Parser} Parse|_source,
            {Type} From|_enumeration) ==> {Expression}, NEW
            :
            ------------------------------ 'Item name in single quotation marks'
            Parse.Wait("'")
            STR name|_of_enum_item = "'" Parse.Ident_ex("-0123456789") "'"
            Parse.Wait("'")
            ---------------------------- 'From certain enumeration ?'
            CASE From != NONE ?
                CASE From.Kind != 'ENUM' ?
                    Parse.Err("Type"._Etype " " From.Names[*]
                    " " ("is not a enumeration"._Eisnot ) )
                ;
                RESULT = search_enum_item(name, From)
                CASE RESULT == NONE ?
                    STR all|_enumeration_items = From.Items[0].Names[0]
                    FOR i IN [1 TO From.Items[].Count-1] :
                        all = all ", " From.Items[i].Names[0] ;
                        
                    Parse.Err("Enumeration"._Eenum2 " " From.Names[*]
                    " " ("does not contain item"._Edoes ) " " name
                    " (" ("should be one of"._Eshould ) ": " all ")")
                    
                ELSE Parse.Compiler.Current_class.Use_imported(From.Base_)
                ;
                ==> ;
            -------------------------- 'Seek all enums in current class'
            {Type} cc|lass_current = comp(Parse).Current_class
            FOR e IN cc.Enums_[] :
                RESULT = search_enum_item(name, e)
                CASE RESULT == NONE ? CONTINUE e ;
                DONE
	                 CASE name IN cc.Enum_items_need_q[] ?
	                      STR cl|ist_of_classes = list_classes_defining_const(
	                      	  name, Parse)
	                 ;
	                 CASE cl != "" ?
	                      Parse.Err("Constant"._Econst " " name 
	                      " " ("is defined in several imported classes, so "
	                      "it must be qualified"._Eis3 ) " (" cl ")")
	                 ;
	                 ==> ;
            -------------------------- 'Seek in all imported classes'
            FOR n_im INDEXING {Type} IN [
            	0 TO cc.Import_[].Count + cc.Test_import_[].Count-1]
            	:
                CASE ?
                [n_im < cc.Import_[].Count] ?
                     {Type} im|ported_class = cc.Import_[n_im]
                [!comp(Parse).Current_fun.Is_test] ? BREAK n_im
                ELSE im = cc.Test_import_[n_im - cc.Import_[].Count]
                ;
                FOR e IN im.Enums_[] :
                    RESULT = search_enum_item(name, e)
                    CASE RESULT == NONE ? CONTINUE e ;
                    DONE     
	                    CASE im !IN cc.Used_imports_[] ?
	                         cc.Used_imports_[] << im ;
	                    CASE name IN cc.Enum_items_need_q[] ?
	                         Parse.Err("Constant"._Econst2 " " name 
	                         " " ("is defined in several imported classes, so it "
	                         "must be qualified"._Eis4 ) )
	                    ;
	                    ==> ;
            ;
            ---------------------------- 'No found'
            Parse.Err("Enumeration item"._Eenum3 " " name 
            " " ("was not found"._Ewasnot ) ) .
            
		FUN list_classes_defining_const(
			STR Name|_of_constant,
			{Parser} Parse|_of_source_of_current_class) ==> STR
			:
			{Type} cc|lass_current = comp(Parse).Current_class
			
            FOR n_im INDEXING {Type} IN [
            	0 TO cc.Import_[].Count + cc.Test_import_[].Count-1]
            	:
                CASE ?
                [n_im < cc.Import_[].Count] ?
                     {Type} im|ported_class = cc.Import_[n_im]
                [!comp(Parse).Current_fun.Is_test] ? BREAK n_im
                ELSE im = cc.Test_import_[n_im - cc.Import_[].Count]
                ;
			    FOR e IN im.Enums_[] :
					CASE search_enum_item(Name, e) != NONE ?
				      	 RESULT = RESULT im.Names[0] ", " ;
			    ;
			;
			RESULT = RESULT.[0 TO *-2] .

        */
        private static Expression obtain_enum_item(Parser Parse, Type From)
        {
            Parse.Wait("'");
            string name = "'" + Parse.Ident() + "'";
            Parse.Wait("'");
            if (From != null)
            {
                if (From.Kind != Type.Kind_type.ENUM)
                {
                    Parse.Err("Type " + From.Names[From.Names.Count - 1] +
                        " is not a enumeration");
                    return null;
                }
                Expression Result = search_enum_item(name, From);
                if (Result == null)
                    Parse.Err("Enumeration " + From.Name() +
                        " does not contain item " + name);
                return Result;
            }
            //---------------------- 'seek all enums in current class'
            foreach (Type e in Parse.Compiler_.Current_class.Enums_)
            {
                Expression Result = search_enum_item(name, e);
                if (Result != null)
                {
                    if (Result.Var_arg.Need_q)
                        Parse.Err("Constant " + name + " is defined in several " +
                            "imported classes, so it must be qualified");
                    return Result;
                }
            }
            //---------------------- 'seek all imported classes'
            foreach (Type imp in Parse.Compiler_.Current_class.Import_)
            {
                foreach (Type e in imp.Enums_)
                {
                    Expression Result = search_enum_item(name, e);
                    if (Result != null)
                    {
                        if (Result.Var_arg.Need_q)
                            Parse.Err("Constant " + name + " is defined in several " +
                                "imported classes, so it must be qualified");
                        return Result;
                    }
                }
            }
            Parse.Err("Enumeration item " + name + " was not found");
            return null;
        }

        /*
        
        FUNCTION obtain_static_fun(
        	{Parser} Parse|_source, 
            {Type} T|ype_of_class) ==> {Expr}, NEW
            :
            -------------------------------------- 'Calling static function'
            STR name|_of_function = Parse.Ident
            {Fun} f|unction_found = T.Find_fun(name, TRUE)
            CASE !f.Modifiers['STATIC'] ?
                Parse.Err("Calling regular function "
                "as a static method"._Ecall3 ": " name)
            ;
            RESULT = Operation_call_fun(f, NONE, Parse) .
        */
        private static Expression obtain_static_fun(Parser Parse, Type T)
        {
            string name = Parse.Ident();
            Function f = T == null ? null : T.Find_fun(name);
            if (f != null && !f.Modifiers[(int)Function.Fun_mod.STATIC])
                Parse.Err("Calling regular function as a static method: " + name);
            return Operation_call_fun(f, null, Parse);
        }

        /*
        
        FUNCTION Operation_call_fun|ction(
        	{Fun} F|unction_to_call,
            {Expr} Obj|ect_this,
            {Parser} Parse|_src) ==> {Expr},
            NEW
            :
            {Fun} cf|unction_current = comp(Parse).Current_fun
            {Type} cc|urrent_class = comp(Parse).Current_class
            CASE !cf.Is_test ? F.Warn_about_deprecated ;
			F.Count_ref += 1
			CASE F.Modifiers['DEBUG_FUN'] && !cf.Compiling_debug && !(
				 comp(Parse).Current_fun.Modifiers['DEBUG_FUN'])
				 ?
			     Parse.Err("Calling DEBUG function from not a DEBUG "
			     "block or DEBUG function"._ECallDebugFun ": " F.Names[0]) ;
			CASE F.Stored_param != NONE ?
			     CASE Parse.Compiler.Current_fun.Modifiers['STATIC'] ?
				      Parse.Err("Calling method with stored parameters from a "
				      "static function"._ECallStoredFromStatic) ;
			     Parse.Compiler.Current_fun.This_used = TRUE ;
            -------------------------------------------- 'Calling method'
            CASE F.Deprecate != "" && F.Modifiers['ABANDONED_FUN'] ?
                 STR m|essage_error = "Function"._Efun 
                     " " F.Whole_name
                 CASE F.Modifiers['ABANDONED_FUN'] ?
                      CASE " " IN F.Deprecate ?
                        Parse.Err( m 
                        " " ("is abandoned"._Eis5a ) 
                        ": " F.Deprecate)
                      ELSE  
                        Parse.Err( m 
                        " " ("is abandoned, use instead"._Eis5 ) 
                        ": " F.Deprecate)
                      ;
                 ;
            ;
            
            CASE !comp(Parse).Current_fun.Modifiers['CALLBACK']
            	 && F != comp(Parse).Current_fun.Ancestor_ 
            	 && F.Modifiers['CALLBACK']
            	 && comp(Parse).Current_class != F.Class
            	 && F.Is_public 
            	 && !comp(Parse).Current_fun.Modifiers['HANDLER']
            	 && !F.Is_public
                 ?
                 Parse.Warn("Calling non-public function which is for "
                 "CALLBACK only not from the class itself"._Ecall4 
                 ": " F.Whole_name) ;
                 
            CASE F.Modifiers['UNCOOKED'] ?
                 Parse.Warn("Calling function"._Wcall 
                 " " F.Whole_name 
                 " " ("which seems is not yet ready (UNCOOKED)"._Wwhich ) ) ;
                 
			--------------------------- 'if calling function is in Waiting_[]'
			CASE F IN cf.Waiting_[] ?
				 INT wpos|ition_of_wait_function = cf.Waiting_[].Find(F)
				 FOR i IN [wpos+1 TO cf.Waiting_[].Count] :
					 CASE cf.Waiting_[i] == NONE ? wpos = i-1
													BREAK i ;
				 ;
				 FOR i IN [wpos DOWNTO 0] :
					 CASE cf.Waiting_[i] != NONE ? cf.Waiting_[].Delete(i)
													cf.Lines_waiting[].Delete(i)
					 ELSE BREAK i ;
				 ;
			;
			--------------------------- 'if calling function has WAIT(...)'
			cf.Call_method_wait(F)
            --------------------------- 'collect array parameter passed through'
            CASE Obj.Var_arg.Is_param && F.Param[0].Is_array ?
                 Obj.Var_arg.Passed_to_other_[] << F
                 Obj.Var_arg.Passed_as_param[] << 0 ;
            CASE Obj.Var_arg.Is_array && Obj.Var_arg.Is_weak ?
                 cf.Passing_arrays[] << Parse.Line
                 cf.Weak_arrays_passing[] << Obj.Var_arg 
                 cf.Passing_to_function_[] << F 
                 cf.Passing_as_param[] << 0 ;
            ---------------- 'Resulting expression with call function operation'
            cf.Last_fun_ = F
            
            RESULT = {Expr}(Operation = 'FUN', Fun_ = F, This_ = Obj,
                At_line = Parse.Line, At_pos = Parse.Pos),
                >> cf.All_expr[]
                
            CASE F.Is_system ? RESULT.Operation = 'SYSTEM_FUN' ;
            CASE Obj.Var_arg.Names[0] == "THIS" ?
                 RESULT.This_ = {Expr}(Operation = 'VAR',
                      	Var_arg = comp(Parse).THIS_var,
                      	Type_obj_=comp(Parse).Current_fun.Class),
                      	OWNED BY RESULT
            ;
            CASE Obj != NONE && F.Modifiers['STATIC'] ?
                 RESULT.This_ = NONE
                 RESULT.Items_[] << Obj
                 Obj.Is_param = TRUE
                 CASE F.Param[].Count == 0 ? 
                      Parse.Err("Function"._Efun2 " " F.Whole_name 
                      " " ("has no parameters"._Ehas ))
                 ;
                 dest|_ex_temp = {Expr}(Operation = 'VAR', Var_arg = F.Param[0])
                 CASE F.Overloaded_[].Count == 0 ?
                 	  cf.Assign_check_compat(dest, Obj) ;
            ;
            CASE F.Param[].Count > RESULT.Items_[].Count ?
                 CASE F.Names[0] == "." ?
                      STR obr|acket_open = "["
                      STR cbr|acket_close = "]"
                 ELSE obr = "("
                 	  cbr = ")" ;
                 	  
                 Parse.Wait_det(obr,
                 "function has parameters"._EFunctionHas
                 ": " F.Whole_name "(" F.param_types ")")
                 
                 CASE obr=="(" ? 
                      INT k|_waiting_brackets = brackets_to_wait(Parse) 
                 ELSE k = 0 ;
                 --------------------------------- '(parameters)'
                 INT positions|_of_parameters[]
                 BOOL assign_form_needed = FALSE
                 INT item|_index = 0
                 FOR i_r IN [RESULT.Items_[].Count TO F.Param[].Count-1] :
                     INT i_p|armeter INDEXING {Var} = i_r
                     item += 1
                     CASE item > 3 && !F.Modifiers['NATIVE_FUN'] ?
                          assign_form_needed = TRUE ;
                     {Var} p|arameter_waiting = F.Param[i_p]
                     FOR j|dummy IN [positions[].Count TO i_r] :
                         positions[] << Parse.Pos ;
                     ----------------- 'assigning form NAME = VALUE ?'
                     PUSH Parse.Pos :
                          BOOL is_assign|_to_parameter_form = FALSE
                          CASE Parse.Next_is_letter && Parse.Ident != "" 
                          	   && !Parse.Next_symbol("==")
                          	   && Parse.Next_symbol("=")
                          	   ?
                               is_assign = TRUE
                               assign_form_needed = TRUE ;
                     ;
                     CASE assign_form_needed && !is_assign ?
                          Parse.Err("Parameter should be passed in form "
                          "Name = expression"._EParamShouldAssign 
                          ": " Parse.Next20 " (" ("parameter is"._MParam) 
                          ": " F.Param[i_p].Names[0] ")")
                     ;
                     CASE is_assign ?
                          STR name_dest|ination_parameter = Parse.Ident
                          Parse.Wait("=") ;
                     CASE Parse.Case_insensitive ? p.Provide_names_lowered ;
                     CASE is_assign && (
                     	  !Parse.Case_insensitive && name_dest !IN p.Names[]
                     	  || Parse.Case_insensitive 
                     	  && name_dest.Lower !IN p.Names_low[])
                     	  ?
                          PUSH Parse.Pos = positions[*] :
	                           Parse.Err("Waiting parameter"._EWaitParam 
	                           ": " p.Names[0] ", " ("but found"._EButFound)
	                           ": " Parse.Next20)
                          ;
                     ;
                     ----------------------------- 'expression passed'
                     INT was_at|_position = Parse.Pos
                     PUSH comp(Parse).Current_fun.Left_side = FALSE :
                     PUSH Parse.Recognizing_param = Parse.Recognizing_param+1:
                          CASE p.Type_.Kind == 'ENUM' ?
                               PUSH comp(Parse).Enumeration_wait
                               		= p.Type_:
                                   {Expr} x|pression_param 
                                   			= Recognize(Parse),
                                   			>> cf.All_expr[]
                               ;
                          ELSE x = Recognize(Parse), >> cf.All_expr[]
                          ;
                          x.Is_param = TRUE
                          ------- 'check if INDEXING variable passed ok'
                          NONE = RESULT.check_assign_indexing(Parse, p, x)
                          ---- 'if array parameter passed as dynamic param ?'
                          CASE x.Var_arg.Is_array && x.Var_arg.Is_param
                               && !x.Is_fixed && !p.Is_fixed
                               ? 
                               x.Var_arg.Passed_as_dynamic = TRUE ;
                     ;
                     ;
                     {kind_type} kind_x|_parameter = x.Type_expr.Kind
                     CASE F.Param[i_p].Type_ != NONE
                     	  && F.Param[i_p].Type_ != x.Type_expr
                     	  && !(F.Param[i_p].Type_.Kind == 'CLASS'
                               || F.Param[i_p].Type_.Kind == 'REAL'
                               && kind_x == 'INT')
                     	  ?
                          PUSH Parse.Pos = was_at :
                          	Parse.Err("Incompatible parameter type"
                          	""._EIncompat ": " Parse.Next20
                          	" " ("Waiting"._E_waiting) 
                          	" " F.Param[i_p].Type_.Whole_name
                          	", " ("actual type is"._E_actual_is)
                          	" " x.Type_expr.Whole_name
                          	", " ("parameter #"._EParamN) (i_p + 1).Str) ;
                     ;
                     --------------------------- 'collect array parameter ...'
                     BOOL array_param|eter = x.Var_arg.Is_param
                     	  array_param &&= x.Is_array  
                     CASE array_param ?
                          x.Var_arg.Passed_to_other_[] << F
                          x.Var_arg.Passed_as_param[] << i_p ;
                          
                     BOOL weak_array = x.Var_arg.Is_array
                     	  weak_array &&= x.Var_arg.Is_weak  
                     CASE weak_array ?
                          cf.Passing_arrays[] << Parse.Line
                          cf.Weak_arrays_passing[] << x.Var_arg 
                          cf.Passing_to_function_[] << F 
                          cf.Passing_as_param[] << i_p ;
                          
                     --------------------- 'check passing read only array'
                     BOOL read_array|_not_accessible = x.Var_arg.Is_array
                     	  read_array &&= x.Var_arg.Modifiers[{var_mod}.'READ']
                     	  
                     	  read_array &&= !cc.Is_descend(x.Var_arg.In_type_,
                     	  	comp(Parse))
                     	  	
                     	  read_array &&= cc.Names[
                     	  	0] !IN x.Var_arg.In_type_.Friends[]
                     	  	    
                     CASE read_array ?
                          Parse.Err("Passing read only array as a parameter"
                          ""._PassROArray)
                     ;
                     CASE x.Is_fixed && x.Var_arg.Size_n[0] == "{" ?
                          Parse.Err("Passing fixed array which size is based "
                          "on ENUMERATION"._EParamFixedArrayOnEnum) ;
                     ---------------------- 'check error / scalar parameters'
                     CASE x.Is_array && !p.Is_array ?
                          Parse.Err("Passing an array in place of a scalar "
                          "parameter"._Epass " (" (i_p+1).Str 
                          ": " F.Param[i_p].Whole_name ")")
                     ;
                     
                     BOOL passing_dyn|amic_array_to_fixed = x.Is_array
                     	  passing_dyn &&= p.Is_fixed
                     	  passing_dyn &&= !x.Is_fixed 
                     CASE passing_dyn && !F.Is_system ?
                          Parse.Warn("Passing a dynamic array in place on a "
                          "fixed array (forget [x TO y] cutting operation "
                          "?)"._Wpass2 "(" (i_p+1).Str 
                          ": " F.Param[i_p].Whole_name ")")
                     ;
                     
                     BOOL passing_sc|alar_to_array = !x.Is_array
                     	  passing_sc &&= p.Is_array  
                     CASE passing_sc ?
                          Parse.Err("Passing a scalar in place of an array "
                          "parameter"._Epass3 
                          " (" (i_p+1).Str ": " F.Param[i_p].Whole_name ")") ;
                     ----------------------- 'for M[x TO y], create temp var'
                     CASE x.Is_fixed && x.Operation == 'INDEX' && (
                          x.Arg3_ != NONE) && !(
                          x.Arg2_.Operation == 'CONST' && (
                          x.Arg2_.Var_arg.Type_.Kind == 'INT') && (
                          x.Arg2_.Var_arg.Int_c == 0) && (
                          x.Arg3_.Is_star_operation))
                          ?
                          temp|_fixed = {Var}(Line = Parse.Line,
                          	   Used_for_w = TRUE, Count_ref = 1,
                               Names[] << "Tempfixed_" cf.Local_var[].Count.Str,
                               Type_ = x.Type_expr,
                               Is_array = TRUE, Is_fixed = TRUE),
                               >> cf.Local_var[]
                               
                          a|ssign_before = {Assign}(Line= 0, Pos= 0, //Line= Parse.Line,
                            Function_ = comp(Parse).Current_fun,
                 			Level = comp(Parse).Current_fun.Current_level,
                            Dest = {Expr}(Operation = 'VAR', Var_arg = temp),
                            Source = x), OWNED BY cf
                               
                          RESULT.Before_assign_[] << a
                          
                          x = {Expr}(Operation = 'VAR', Var_arg = temp),
                              OWNED BY cf
                     ;
                     ---------------------------------- 'convert INT -> REAL'
                     BOOL is_i2r|eal = !x.Is_array
                     	  is_i2r &&= x.Type_expr.Kind == 'INT'   
                     	  is_i2r &&= p.Type_.Kind == 'REAL' 
                     CASE is_i2r ?
                          {Expr} int_x|_parameter = x
                          
                          x = {Expr}(Operation = 'INT2REAL', Arg1_ = int_x,
                          	  Type_obj_ = comp(Parse).TYPE_REAL),
                          	  OWNED BY cf
                     ;
                     ---------------------------------- 'parameter x is ready'
                     RESULT.Items_[] << x
                     CASE i_p < F.Param[].Count-1 ?
                          Parse.Wait_det(",", 
                          "not enough parameters"._ENotEnough
                          ": " F.Whole_name) ;
                 ;
                 CASE Parse.Next_symbol(",") ?
                      CASE F.Modifiers['STATIC'] ?
                           Parse.Err("Too many parameters to call "
                           "function"._Etoo ": " F.Whole_name)
                      ELSE Parse.Err("Too many parameters to call "
                           "method"._Etoo2 ": " F.Whole_name) ;
                 ;
                 FOR i IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait_det(cbr, 
                 "too many parameters to call function"._ETooMany
                 ": " F.Whole_name)
                 --------------------------- 'check restrictions'
                 check_actual_parameters(RESULT, Parse, positions[])
                 CASE F.Restricts > 0 ?
                      F.Check_actual_parameters_restrictions(RESULT.Items_[]) 
                 ;
            ELSE Parse.Skip_sp
                 CASE Parse.Next_char == "(" ?
                      ------------------------ 'prevent erroneous s.foo(s)'
                      CASE F.Result.Type_.Kind == 'STR' ?
                       Parse.Err("Symbol '(' should not follow the "
                       "function call if the function returns STR result "
                       "and has no explicit parameters"._Esymbol)
                      ;
                      Parse.Wait("(")
                      Parse.Wait(")")
                 ;
            ; 
            --------------------------------------- 'has it STORED parameter ?'
            CASE F.Modifiers['STORE'] ?
                 cf.Calls_stored_fun = TRUE
                 cc.Cached_parameters += 1
                 
                 cached|_parameter = {Var}(Line = Parse.Line,
                    Is_param = TRUE, Is_stored_param = TRUE,
                    Names[] << "_cache_" cc.Cached_parameters.Str,
                    Type_ = comp(Parse).TYPE_INT,
                    In_type_ = cc),
                    >> cc.Field[]
                    
                 PUSH cf.Class.Prefix_f = "i" :
                      cached.Set_final_name(cf.Class.Next_final_name(
                      	cached.Names[], TRUE))
                 ;
                 CASE F.Stored_initial_value != 0 ?
                      cached.Initial_ = {Expr}(Operation = 'CONST',
                      Var_arg = {Var}(Line = Parse.Line, Is_const = TRUE,
                      Type_ = comp(Parse).TYPE_INT,
                      Int_c = F.Stored_initial_value)),
                      OWNED BY cached ;
                      
                 {Expr} obj_x|_this = {Expr}(Operation = 'VAR',
                 	    Var_arg = comp(Parse).THIS_var,
                 	    Type_obj_ = cc), OWNED BY cached
                 	    
                 x = {Expr}(Operation = 'FIELD', Var_arg = cached,
                     Pass_by_ref = TRUE,
                     Is_param = TRUE,
                     Arg1_ = obj_x), OWNED BY cf
                     
                 RESULT.Items_[] << x
            ; .
            
        METHOD check_assign_indexing(
        {Parser} Parse|r_code,
        {Var} p|arameter_destination,
        {Expr} s|ource_expression) ==> BOOL, RECURSIVE
        	:
            CASE ?
            [p.Indexing_[].Count > 0 && s.Operation IN ['VAR']] ?
                RESULT = TRUE
                CASE ?
                [s.Operation == 'SYSTEM_FUN' 
                 && s.Fun_ == comp(Parse).SYSFUN_Index] ?
                    RESULT = TRUE
                    {Type} x_t|ype_indexing = s.Items_[0].Type_expr
                    FOR sx IN s.Var_arg.Indexing_[] :
                        CASE sx.Is_descend(x_t, comp(Parse)) ? ==> ;
                    ;
                    Parse.Err("Passing INDEXING variable as a parameter "
                    "which INDEXING attribute is not compatible"
                    ""._EPassingIndexWrong) ==>
                    
                [s.Var_arg.Indexing_[].Count == 0] ?
                     CASE p.Indexing_[].Count == 1 
                     	  && p.Indexing_[0].Kind == 'INT'
                     	  ?
                          ==>
                     ;
                     STR line_a|dding = (Parse.Line + 1 + Count_char(
                     	Parse.Source[Parse.Line].[0 TO Parse.Pos], #LF)).Str
                     	
                     CASE line_a !IN comp(
                          Parse).Current_fun.Warnings_indexing2[]
                          ?
                          comp(Parse).Current_fun.Warnings_indexing2[]<< line_a
                     ; 
                     //Parse.Warn("It is desired to pass INDEXING variable "
                     //"in place of INDEXING parameter"
                     //""._WMustIndexingParam
                     //": " Names_types(p.Indexing_[]) "<--" p.Names[0])
                  	 ==> ;
                FOR px IN p.Indexing_[] :
                    FOR sx IN s.Var_arg.Indexing_[] :
                        CASE sx.Is_descend(px, comp(Parse)) ? ==> ;
                    ;
                ;
            [p.Indexing_[].Count == 0 && s.Operation IN  ['VAR', 'FIELD']] ?
                CASE s.Var_arg.Indexing_[].Count > 0 ?
                     //Parse.Warn("Passing INDEXING variable as a parameter "
                     //"which is not marked for indexing"._WPassIndexToNotIndex)
                     
                     RESULT = TRUE ;
            [s.Operation == 'BINARY'] ?
                RESULT = check_assign_indexing(Parse, p, s.Arg1_)
                RESULT ||= check_assign_indexing(Parse, p, s.Arg2_)
                CASE !RESULT || p.Indexing_[].Count == 0 ? ==> ;
                CASE s.Sign !IN ['PLUS', 'MINUS'] ?
            	     Parse.Err("When calculating indexes based on a variable "
            	     "marked for INDEXING +/- operations are allowed only "
            	     "for it"._EOnlyPlusMinusIndex)
                ;
            ; .
                     
                
                                      
            
        FUN param_types({Fun} F|unction) ==> STR :
        	FOR p IN F.Param[] :
        	    CASE RESULT != "" ? RESULT = RESULT ", " ;
        	    RESULT = RESULT p.Type_.Names[0] ; .
            
        FUN debug|_string(STR S|tring_to_pass_if_DEBUG) ==> STR :
        	SILENT:
        		DEBUG: RESULT = S ;
        	; .
            
        FUN Check_structure_clone_dismiss
        	    |_used_in_right_side_of_assignment(
        {Expr} E|_may_be_STRUCT_wo_clone_dismiss_only_at_the_top_level,
        {Parser} Parse|_to_message_erros)
        	:
        	CASE ?
        	[E.Type_expr.Kind != 'STRUCTURE'] ? ==>
        	[E.Operation == 'SYSTEM_FUN'
        	 && E.Fun_.System_fun IN ['SYSFUN_Clone', 'SYSFUN_Dismiss']]
        		 ?
        	     ==>
        	[Parse.Clone_by_default] ?
        	     {Expr} cloning|_expression = {Expr}(Operation= E.Operation,
        	     	Sign= E.Sign, Arg1_= E.Arg1_, Arg2_= E.Arg2_, Arg3_= E.Arg3_,
        	     	This_= E.This_, Type_obj_= E.Type_expr,
        	     	Var_arg= E.Var_arg, Fun_= E.Fun_),
        	     	OWNED BY E
        	     	
        	     FOR it IN E.Items_[] : cloning.Items_[] << it ;
        	     -------------------------- 'E -> call Clone'
        	     E.Operation = 'SYSTEM_FUN'
        	     E.Fun_ = Parse.Compiler_.{Compiler}.SYSFUN_Clone
        	     E.Type_obj_ = cloning.Type_obj_
        	     E.Items_[].Clear
        	     E.Items_[] << cloning ==>
        	[E.Operation IN ['FUN', 'BASE_FUN']] ? ==>
        	[E.Operation == 'NEW_OBJ'] ? ==>
        	;
        	CASE E.Var_arg.Names[0].[0] == "_" ? ==> ; // _extr_...
        	
        	Parse.Err("Using STRUCTURE without .Clone or .Dismiss"
        	     	""._EStrucWoCloneDismiss0 
        	     	"" debug(" [2] operation=" E.Operation.Name
        	     	" var=" E.Var_arg.Whole_name)) .
        	
        	
        FUN check_actual_parameters( 
            {Expr} Op|eration_function_call, {Parser} Parse|r_of_source,
            INT Pos|itions_of_parameters[])
            :
            CASE Op.Fun_.Overloaded_[].Count > 0 ?
                 NONE = find_matching_overloaded(Op, Parse)
            ;
            CASE Op.Fun_.Overloaded_[].Count > 0 ?
                 STR e|rror_text = Op.Fun_.Class.Whole_name
                 e = e "." Op.Fun_.Whole_name
                 Parse.Err("Ambiguous overloaded function call: " e ) ;
            ------------------------------- 'if actual parameters are suitable?'
            FOR x IN Op.Items_[] :
                PUSH Parse.Pos = Pos[x.Index] :
                     {Var} p|arameter_formal = Op.Fun_.Param[x.Index]
                     ----------------------------- 'check types parameter'
                     d|estination_TEMP = {Expr}(Operation = 'VAR',
                      	   						Var_arg = p)
	                            
                     comp(Parse).Current_fun.Assign_check_compat(d, x)
                     ------------------------------ 'check array params'
                     CASE x.Is_array != p.Is_array ?
                          Parse.Err("Array is not compatible "
                          "with scalar"._Earr ": " Parse.Next20)
                     ;
                     CASE p.Is_array && !p.Is_fixed && x.Is_fixed ?
                          Parse.Err("Passing fixed array as a "
                          "dynamic array"._Epass4 ": " Parse.Next20)
                     ;
                ;
            ; .
            
        FUN find_matching_overloaded(
        {Expr} Op|eration_function_call, 
        {Parser} Parse|r_of_source)
        ==> {Fun}	
        	:
        	FOR vf IN Op.Fun_.Overloaded_[] :
        	    FOR p IN vf.Param[] :
        	        temp|_expression = {Expr}(Operation = 'VAR',
        	        	Var_arg = p)
        	        	
        	    	CASE !vf.Check_compat(temp, Op.Items_[p.Index]) ?
        	    	     BREAK p, CONTINUE vf ;
        	    ;
        	    DONE
	        		{Fun} cf|unction_current = Parse.Compiler.Current_fun
	        		cf.Call_functions_[].Remove(Op.Fun_)
	        		cf.Call_functions_[] << vf
	        	    Op.Fun_ = vf 
	        	    RESULT = vf ==> ;
        	    
        	Parse.Err("There are no compatible overloaded types for such actual"
        	" parameters passed for the function"._ENoCompatTypes
        	": " Op.Fun_.Names[0]) .
                     
                     
                
        */
        public static Expression Operation_call_fun(Function F,
                Expression Obj, Parser Parse)
        {
            Function cf = Parse.Compiler_.Current_fun;
            if (!cf.Call_.Contains(F)) cf.Call_.Add(F);
            Expression Result = new Expression();
            Result.Operation = Operation_kind.FUN;
            Result.At_line = Parse.Line;
            Result.At_pos = Parse.Pos;
            Result.Fun_ = F;
            Result.This_ = Obj;
            if (Parse.Symbol("("))
            {
                if (F != null)
                {
                    foreach (Variable p in F.Param)
                    {
                        int pos = Parse.Pos;
                        Expression x = Recognize(Parse);
                        Result.Items_.Add(x);
                        if (x != null && x.Operation == Operation_kind.NEW)
                        {
                            int sav = Parse.Pos;
                            Parse.Pos = pos;
                            Parse.Err("Can not pass new object as a parameter: " + Parse.Next20());
                            Parse.Pos = sav;
                        }
                        int sav_pos = Parse.Pos;
                        //------------------------------ 'check_compatibility types'
                        Expression L = new Expression();
                        L.Operation = Operation_kind.VAR;
                        L.Var_arg = p;
                        Parse.Compiler_.Current_fun.Assign_check_compat(L, x, pos);
                        //------------------------------ 'check array params'
                        Parse.Pos = pos;
                        if (x != null && x.Is_array() != p.Is_array)
                            Parse.Err("Array is not compatible " +
                                "with scalar: " + Parse.Next20());
                        if (p.Is_array && !p.Is_fixed && x.Is_fixed())
                            Parse.Err("Passing fixed array as a " +
                                "dynamic array: " + Parse.Next20());
                        Parse.Pos = sav_pos;
                        if (p != F.Param[F.Param.Count - 1])
                            Parse.Wait(",");
                    }
                }
                Parse.Wait(")");
            }
            else if (F != null && F.Param.Count > 0)
                Parse.Err("Parameters are not specified");
            return Result;
        }

        /*
        FUNCTION search_enum_item(STR Name|_of_item,
            {Type} E|numeration) ==> {Expression}, NEW
            :
            ----------------------------- 'Search enum item and make a constant'
            {Var} it|em_found = E.Search_enum_item(Name)
            CASE it != NONE ?
                RESULT = {Expression}(Operation = 'CONST', Var_arg = it) ; .
        */
        private static Expression search_enum_item(string Name, Type E)
        {
            Variable it = E.Search_enum_item(Name);
            if (it != null)
            {
                Expression Result = new Expression();
                Result.Operation = Operation_kind.CONST;
                Result.Var_arg = it;
                return Result;
            }
            return null;
        }

        /*
        
        FUNCTION space_between_quote_and_dot(
        {Parser} Parse|_on_dot) ==> BOOL
            :
            FOR x IN [Parse.Pos-1 DOWNTO 0] :
                CASE Parse.Source[Parse.Line].[x] ?
                [#SP, #TAB]: BOOL sp|acs_found = TRUE
                [#QU]: RESULT = sp ==>
                ELSE ==> ;
            ; .
            
        METHOD Chain_operations(
        	{Parser} Parse|_source, BOOL Br|acket_approved) ==> {Expr},
        	NEW, RECURSIVE
        	:
            ------------------------------------ 'Brackets are only for array[]'
            RESULT = THIS
            CASE comp(Parse).Current_fun != NONE ?
	             comp(Parse).Current_fun.Set_last_expr(RESULT)
	             comp(Parse).Current_fun.All_expr[] << RESULT ;
            BOOL br|ackets_approved = Br || Operation == 'ARRAY'
            STR prev_next_char = ""
            STR was_next_char = ""
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                Parse.Skip_sp
                BOOL skip_set_last_arg = Parse.Prev_char <= " "
                CASE ! br && RESULT.Is_array && RESULT.Operation != 'INDEX' 
                     && Parse.Next_char != "["
                	 && !Parse.Allow_omit_array_brackets
                	 ?
                     Parse.Wait("[") ;
                prev_next_char = was_next_char
                was_next_char = Parse.Next_char
                CASE was_next_char ?
                ["."]:
                	CASE Operation=='CONST' && Var_arg.Type_.Kind=='STR' 
                	     && space_between_quote_and_dot(Parse)
                	     ? 
                	     //DEBUG: "#QU then SPACES then '.' !!!"#NL ;
                	     ==> ;
                	CASE !skip_set_last_arg ?
                	     comp(Parse).Current_fun.Last_arg = RESULT ;
                    ------------------------------------- '.'
                    //PUSH comp(Parse).Current_fun.Left_side = FALSE :
	                   CASE Parse.Symbol("..") ?
	                        comp(Parse).Current_fun.Set_last_dest(
	                            RESULT, TRUE)
	                   ;
	                   BOOL is_str_idx = FALSE
	                   PUSH Parse.Pos :
	                       CASE Parse.Symbol(".") && Parse.End_of_line ?
	                            BREAK x ;
		                   --------------- 'new strings indexing syntax s.[i] ?'
		                   CASE Parse.Next_char == "[" 
		                        && RESULT.Type_expr.Kind=='STR' 
		                        && !RESULT.Is_array 
		                        ? 
		                        is_str_idx = TRUE ;
	                   ;
	                   CASE is_str_idx ? 
	                        NONE = Parse.Symbol(".")
	                        CONTINUE x ;
	                   CASE RESULT.Operation ?
	                   ['VAR', 'INDEX', 'FIELD', 'NEW_OBJ', 'FUN',
	                   	'BASE_FUN', 'SYSTEM_FUN', 'AS', 'NOT', 'NOT_B', 
	                    'NEG']:
	                       RESULT = chain_field_or_fun(RESULT, Parse),
	                           >> comp(Parse).Current_fun.All_expr[]
	                           
	                       {Expr} temp|_in_chain = may_be_trapping_scalar(
	                           RESULT, Parse),
	                           >> comp(Parse).Current_fun.All_expr[]
	                           
	                       RESULT = temp
	                       
	                       comp(Parse).Current_fun.Set_last_expr(
	                          RESULT)
	                          
	                   ['CONST', 'BINARY']:
	                       RESULT = chain_fun_of_val(RESULT, Parse),
	                             >> comp(Parse).Current_fun.All_expr[]
	                             
	                       comp(Parse).Current_fun.Set_last_expr(
	                          RESULT)
	                          
	                   ['ARRAY', 'UNKNOWN']: Parse.Err("Internal error - "
	                           "can not continue chain"._Einternal2 
	                           ": " Parse.Next20) 
	                           
	                       BREAK x
	                       
	                   ['INT2REAL']:
	                        RESULT = Arg1_.Chain_operations(Parse, FALSE), 
	                       		>> comp(Parse).Current_fun.All_expr[]
	                   ;
                   //;
                   br = FALSE
                ["["]:
                   CASE RESULT.Type_expr.Kind=='STR' && !RESULT.Is_array
                        && prev_next_char != "."
                        ? 
                        Parse.Warn("All indexing/range operations [...] with "
                        "strings should be separated by a dot (.) character "
                        "like s.[i]"._EIndexingStringsAfterDot) ;
                   ------------------------------------- '['
                   PUSH comp(Parse).Current_fun.Left_side = FALSE :
	                    {Expr} r|esulting_expr = RESULT
	                    BOOL scalar|_expression = ! r.Is_array
	                    	 scalar &&= r.Type_expr.Kind != 'STR'  
	                    CASE scalar ? 
	                         Parse.Err("Indexing can not be applied for "
	                         "scalar"._Eindex ": " Parse.Next20)
	                    ;
	                    Parse.Skip_char
	                    CASE Parse.Symbol("]") ?
	                         BOOL em|pty_brackets = TRUE
	                    
	                    ELSE RESULT = chain_index(RESULT, Parse),
	                         >> comp(Parse).Current_fun.All_expr[]
	                         
	                         comp(Parse).Current_fun.Set_last_expr(RESULT)
	                         
	                         RESULT = may_be_trapping_array(RESULT, Parse),
	                         >> comp(Parse).Current_fun.All_expr[]
	                    ;
	                    CASE em && ! r.Is_array ?
	                        Parse.Err("Operation [] is not applicable "
	                        "for a scalar"._Eoper5)
	                    ;
                   ;
                   br = TRUE
                ELSE 
                     CASE RESULT.Is_array && !br
                     	  && !Parse.Allow_omit_array_brackets
                     	  ?
                          Parse.Err("Waiting for '['"._Ewait4 
                          ": " Parse.Next20)
                     ;
                     BREAK x ;
            ;
            CASE RESULT.Operation == 'FIELD' 
                 && Parse.Next_char=="."
                 ?
                 comp(Parse).Current_fun.Last_arg = RESULT.Arg1_ ;
            .
            
        BOOL indexing_found
        
        METHOD check_indexing(
        {Parser} Parse|_source, 
        {Expr} e|xpression_index, {Expr} a|rray_to_index) ==> BOOL, RECURSIVE
            :
            CASE ?
            [a.Var_arg.Size_n[0] == "{"] ? RESULT = TRUE
            [e.Operation IN ['VAR', 'FIELD']] ?
                BOOL is_arr|ay_a = a.Is_array
                CASE !is_arr && a.Type_expr.Kind == 'STR' ?
                     CASE e.Var_arg.Indexing_[].Count == 0 ? ==> ;
                     indexing_found = TRUE     
                     FOR ex IN e.Var_arg.Indexing_[] :
                         CASE ex.Kind == 'STR' ?  ==> ;
                     ;     
                     Parse.Err("Indexing characters with variable having "
                     "INDEXING attribute not referring to STR"._EIndexingStr) 
                     ==>
                ;     
                CASE e.Var_arg.Indexing_[].Count == 0 ?
                     ---------------------- 'indexing warning added'
                     //Parse.Warn("It is desired to index arrays with variables "
                     //"only which are marked with 'INDEXING {type}' following "
                     //"its declaration"._WIndexingDesired)
                     STR line_a|dding = (Parse.Line + 1 + Count_char( 
                     	Parse.Source[Parse.Line].[0 TO Parse.Pos],
                     	#LF)).Str "(" e.Var_arg.Names[0] ")"
                     	
                     CASE !e.Is_index && line_a !IN comp(
                     	  Parse).Current_fun.Warnings_indexing1[]
                     	  ?
                     	  comp(Parse).Current_fun.Warnings_indexing1[] << line_a
                     ; 
                     	
                     RESULT = TRUE ==> ;
                indexing_found = TRUE
                FOR ex IN e.Var_arg.Indexing_[] :
                    CASE ex.Is_descend(a.Type_expr, comp(Parse)) ?
                     	 RESULT = TRUE ==> ;
                ;
                STR er|ror_text = "Indexing array with the variable of "
                	"incompatible indexing type"._EIndexIncompat 
                	": " Names_types(e.Var_arg.Indexing_[])
                	"<--" e.Var_arg.Whole_name 
	                " (" ("defined at line"._EDefinedAtLine) 
	                "  " (e.Var_arg.Line+1).Str 
	                " ), " ("waiting"._Ewaiting)
	                 
                er = er " " a.Type_expr.Whole_name
                CASE e.Var_arg.Automatic_indexing ?
                     Parse.Index_warn(er)
                ELSE Parse.Err(er) ;
                
            [e.Operation == 'BINARY'] ?
                CASE !a.Is_array ? ==> ;
                PUSH indexing_found = FALSE :     
	                 RESULT = check_indexing(Parse, e.Arg1_, a)
	                 RESULT ||= check_indexing(Parse, e.Arg2_, a)
	                 CASE RESULT || !indexing_found ? ==> ;
                ;
            	CASE ?
            	[e.Sign !IN ['PLUS', 'MINUS']]
            		?
            	    Parse.Err("When indexing with the variable marked for "
            	    "INDEXING +/- operations only are allowed for it"
            	    ""._EOnlyPlusMinusIndexing)
            	     
            	     RESULT = TRUE
            	     
            	[e.Arg1_.Var_arg.Indexing_[].Count > 0 
            	 && e.Arg2_.Var_arg.Indexing_[].Count > 0
            	 && Indexings_different(e.Arg1_.Var_arg.Indexing_[],
            	 		e.Arg2_.Var_arg.Indexing_[], FALSE) ] ?
            	    indexing_found = TRUE
            	    
            	    Parse.Err("Adding or subtracting integer values with "
            		"different indexing purposes"._EDifferentIndexes)
            	     
            		RESULT = TRUE ;
            ; .
            
        	FUN Indexings_different(
        	{Type} I1|_indexings_dyn[], {Type} I2|_indexings_dyn[],
        	BOOL Exact|_equality_required) ==> BOOL
        		:
        		BOOL i2_founds[]
        		FOR x_i2|dummy IN I2[] : i2_founds[] << FALSE ;
        		BOOL found|_any = FALSE
        		FOR t IN I1[] :
        		    FOR t2 IN I2[] :
        		    	CASE t == t2 ?
        		    	     i2_founds[t2.Index] = TRUE
        		    	     found = TRUE
        		    	     CASE !Exact ? ==> ;
        		    	     BREAK t2 ;
        		    ;
        		;
        		CASE !found ? RESULT = TRUE ==> ;
        		CASE !Exact ? ==> ;
        		FOR i IN [0 TO i2_founds[].Count-1] :
        		    CASE !i2_founds[i] ? RESULT = TRUE ==> ;
        		; .     
            
        	FUN Names_types({Type} T|ypes_dyn_array[]) ==> STR :
        		CASE T[].Count <= 1 ? RESULT = T[0].Names[0] ==> ;
        		FOR t IN T[] :
        		    RESULT = RESULT t.Names[0] "," ;
        		RESULT = "(" RESULT.[0 TO *-1] ")" .
        		    
                     
        */
        public static Expression Chain_operations(Expression E, Parser Parse)
        {
            Expression Result = E;
            bool br = E != null && E.Operation == Operation_kind.ARRAY;
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                Parse.Skip_sp();
                if (!br && Result != null && Result.Is_array() && Parse.Next_char() != "[")
                    Parse.Wait("[");
                if (Parse.Next_symbol(".[")) Parse.Skip_char();
                switch((Parse.Next_char() + " ")[0])
                {
                    case '.':
                        int pos = Parse.Pos;
                        try
                        {
                            if (Parse.Symbol(".") && Parse.End_of_line()) return Result;
                        }
                        finally { Parse.Pos = pos; }
                        if (Result != null)
                        switch (Result.Operation)
                        {
                            case Operation_kind.VAR:
                            case Operation_kind.INDEX:
                            case Operation_kind.FIELD:
                            case Operation_kind.NEW:
                            case Operation_kind.FUN:
                            case Operation_kind.AS:
                                Result = chain_field_or_fun(Result, Parse);
                                break;
                            case Operation_kind.CONST:
                            case Operation_kind.BINARY:
                                Result = chain_fun_of_val(Result, Parse);
                                break;
                            default:
                                Parse.Err("Internal error - can not continue chain: "
                                    + Parse.Next20());
                                break;
                        }
                        br = false;
                        break;
                    case '[':
                        if (!Result.Is_array() && Result.Type_expr() != null && 
                            Result.Type_expr().Kind != Type.Kind_type.STR)
                            Parse.Err("Indexing can not be applied for scalar: " + Parse.Next20());
                        Parse.Skip_char();
                        if (Parse.Symbol("]"))
                        {
                            if (!Result.Is_array())
                                Parse.Err("Operation [] is not applicable for a scalar");
                        }
                        else
                        {
                            Result = chain_index(Result, Parse);
                        }
                        br = true;
                        break;
                    case '+':
                    case '-':
                        bool p = Parse.Next_symbol("++") || Parse.Next_symbol("--");
                        if (p)
                            apply_inc_dec(Result, Parse);
                        else return Result;
                        br = false;
                        break;
                    default:
                        if (Result != null && Result.Is_array() && !br)
                            Parse.Err("Waiting for '[': " + Parse.Next20());
                        return Result;
                }
            }
            return Result;
        }

        /*
        
        METHOD chain_index({Expr} E|xpression,
            {Parser} Parse|_src) ==> {Expr}, NEW
            :
            ------------------------------------- '[ was earlier, now an index'
            PUSH comp(Parse).Current_array = E :
            PUSH comp(Parse).Current_fun.Left_side = FALSE :
                INT start|_pos = Parse.Pos
                CASE E.Var_arg.Size_type_.Kind == 'ENUM' ?
                     {Expr} i|ndex_expr = Recognize(Parse),
                                 >> comp(Parse).Current_fun.All_expr[]
                                 
                     CASE E.Var_arg.Size_type_.Kind == 'ENUM' ?
                          BOOL same_t|ype = i.Type_expr.Names[0] == (
                          	   E.Var_arg.Size_type_.Names[0]) && (
                            i.Type_expr.Names[1] == (
                               E.Var_arg.Size_type_.Names[1])) && (
                            i.Type_expr.Base_ == (
                               E.Var_arg.Size_type_.Base_))
                     ELSE same_t = i.Type_expr == E.Var_arg.Size_type_
                	 ; 
                     CASE !same_t && ! ((
                          i.Operation == 'FUN') && (
                          i.Fun_ == comp(Parse).SYSFUN_Index))
                          ?
                          Parse.Err("Invalid index type"._Einvalid2 
                          ": " i.Type_expr.Whole_name
                          "(" ("required"._Erequir ) 
                          ": " E.Var_arg.Size_type_.Whole_name ")")
                     ;
                ELSE i = Recognize_typed(Parse, 'INT'),
                       >> comp(Parse).Current_fun.All_expr[] ;
                       
                PUSH indexing_found :
                     NONE = E.check_indexing(Parse, i, E) ;

                RESULT = {Expr}(Operation = 'INDEX', Arg1_ = E, Arg2_ = i,
                    At_line = Parse.Line, At_pos = start)
                    
                CASE Parse.Symbol("TO") ?
                     CASE E.Is_array || E.Type_expr.Kind == 'STR' ? NONE
                     
                     ELSE Parse.Err("Subrange is not applicable"._Esub ": "
                          "" Parse.Next20)
                     ;
                     RESULT.Arg3_ = Recognize_typed(Parse, 'INT'),
                          >> comp(Parse).Current_fun.All_expr[] ;
            ;
            ;
            Parse.Wait("]") .
        */
        static int CNT_chain_index;

        private static Expression chain_index(Expression E, Parser Parse)
        {
            if (CNT_chain_index++ == 122)
            { }
            int start = Parse.Pos;

            Expression i = null;
            Expression save = Parse.Compiler_.Current_array;
            Parse.Compiler_.Current_array = E;
            Expression Result = new Expression();
            try
            {
                if (E.Var_arg != null && E.Var_arg.Size_type_ != null && E.Var_arg.Size_type_.Kind == Type.Kind_type.ENUM)
                {
                    i = Expression.Recognize(Parse);
                    if (i != null && i.Type_expr() != E.Var_arg.Size_type_)
                        Parse.Err("Invalid index type: " + 
                            i.Type_expr().Name() + " (required: " + E.Var_arg.Size_type_.Name() + ")");
                }
                else i = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                Result.Operation = Operation_kind.INDEX;
                Result.Arg1_ = E;
                Result.Arg2_ = i;
                Result.At_line = Parse.Line;
                Result.At_pos = start;
                if (Parse.Symbol("TO"))
                {
                    if (E.Is_array() && !E.Is_fixed() || E.Type_expr().Kind == Type.Kind_type.STR) { }
                    else Parse.Err("Subrange is not applicable: " + Parse.Next20());
                    Result.Arg3_ = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                }
            }
            finally { Parse.Compiler_.Current_array = save; }
            Parse.Wait("]");
            return Result;
        }

        /*
        
FUNCTION chain_field_or_fun(
{Expr} Value|_start_from,
{Parser} Parse|_src) ==> {Expr}, NEW
    :
    //{Type} cc|lass_current = comp(Parse).Current_class
    {Fun} cf|unction_current = comp(Parse).Current_fun
    {Expr} v|ariable_start_from = Value
    --------------------------------------- 'Next is .Field or .fun(...'
    BOOL v_is_prefix = v.Type_expr.Kind !IN ['CLASS', 'STRUCTURE']
         v_is_prefix ||= v.Is_array
    CASE v_is_prefix ?
         RESULT = chain_fun_of_val(v, Parse) ==> ;
    INT pos|ition_dot = Parse.Pos
    Parse.Wait(".")

    INT p_excl|amation_position = Parse.Pos
    BOOL is_not|_operation_next = Parse.Symbol("!")
    PUSH cf.Count_not :
         CASE is_not ?
              CASE cf.Count_not > 0 ?
                   Parse.Err("Suspicious using '!' operation several times "
                   "sequentionally"._ENotSuspect1) ;
              cf.Count_not += 1
         ;
         
         {Expr} r|eturning_temp = chain_field_or_fun_1(v, Parse, pos)
		 CASE is_not ? 
		      CASE r.Operation !IN ['FUN', 'SYSTEM_FUN', 'BASE_FUN', 'FIELD',
		           'INDEX'] || r.Type_expr.Kind != 'BOOL'
		           ?
		           PUSH Parse.Pos = p_excl :
		           		Parse.Err("Operation '!' is not applicable")
		           ;
		      ;
		      {Expr} fun_c|all_to_invert = r
		      r = {Expr}(Operation= 'NOT', Arg1_= fun_c), >> cf.All_expr[]
		 ;
		 RESULT = r
    ; .
        
FUNCTION chain_field_or_fun_1(
{Expr} v|alue_from_which_chain_is_starting,
{Parser} Parse|_src,
INT pos|ition_before) ==> {Expr}, NEW
	:
	{Type} cc|lass_current = comp(Parse).Current_class
    {Fun} cf|unction_current = comp(Parse).Current_fun
    CASE Parse.Next_symbol("{") ?
         ----------------------- 'typecast: zzz.{Class} ... '
         BOOL ar|ray_V_is = v.Is_array
         CASE ar || v.Type_expr.Kind != 'CLASS' ?
             Parse.Err("Typecast operation is not applicable"._Etype4
             ": " Parse.Next20) ;

         RESULT = {Expr}(Operation = 'AS', Arg1_ = v,
             Type_obj_ = cc.Find_type(
                 Parse.Scan_type), At_line = Parse.Line, At_pos = pos)

         CASE RESULT.Type_expr.Kind !IN ['CLASS', 'STRUCTURE'] ?
             Parse.Err("Typecast not to class/structure type"._Etype5
                 ": " RESULT.Type_obj_.Whole_name)
         ;
         CASE ! RESULT.Type_expr.Is_descend(v.Type_expr, comp(Parse)) ?
              CASE !v.Type_expr.Is_descend(RESULT.Type_expr, comp(Parse))
                   ?
                   Parse.Err("Typecast not to inherited or descendant "
                   "class"._Etype6
                   ": " v.Type_expr.Whole_name
                   " -> " RESULT.Type_expr.Whole_name)
              ;
         ;
         ==> ;
    CASE Parse.Next_symbol("[") ?
         {Fun} ffun|ction = v.Type_expr.Search_fun(
               ".", CASE_SEN | ONLY_METHODS, TRUE)

         CASE ffun == NONE ?
              Parse.Err("Type is not a class or has not a dot method "
              ".[]"._ETypeHasNoDot ": " v.Type_expr.Whole_name)

         ELSE cf.This_used = TRUE ;
         CASE v.Is_array ?
              Parse.Err(".[] is not applicable to an array"
              ""._EDotToArray)
         ;
         STR name|_of_field_or_method = "."
    ELSE name = Parse.Ident ;
    ---------------------------------------------- 'field'
    CASE ! v.Is_array && ffun == NONE ?
         {Var} f|ield_of_obj = v.Type_expr.Search_field(name)
         CASE f.In_type_ != v.Type_expr
              && !v.Type_expr.Is_descend(f.In_type_, comp(Parse))
              ?
              f = NONE ;
    ;
    CASE f != NONE ?
         f.Count_ref += 1
         BOOL is_acc|sessible = f.Is_public
              is_acc ||= cc.Is_descend(v.Type_expr, comp(Parse))
              is_acc ||= cc.Is_descend(f.In_type_, comp(Parse))
              //is_acc ||= cc.Names[0] IN v.Type_expr.Friends[]

              is_acc ||= f.In_type_.Kind == 'STRUCTURE'
                && cc.Is_descend(f.In_type_.In_class_, Parse.Compiler)

              //is_acc ||= f.In_type_.Kind == 'STRUCTURE'
              //  && cc.Names[0] IN f.In_type_.Friends[]

         {Type} ccc|_base = cc
         FOR x|dummy IN Parse.Compiler.All_classes[] :
             CASE is_acc || ccc == NONE ? BREAK x ;
             CASE ?
             [v.Var_arg.In_type_ != NONE 
             && ccc.Names[0] IN v.Var_arg.In_type_.Friends[]] ?
                  is_acc = TRUE
             [ccc.Names[0] IN v.Type_expr.Friends[]] ?
                  is_acc = TRUE ;
             ccc = ccc.Base_ ;

         CASE !is_acc ?
              Parse.Err("Field is not public"._Efield4 ": " name) ;

         RESULT = {Expr}(Operation = 'FIELD',
             Arg1_ = v, Var_arg = f,
             At_line = Parse.Line, At_pos = pos), OWNED BY v ==>
    ;
    ---------------------------------------------- 'function'
    CASE v.Type_expr.Kind == 'CLASS' ?
         ffun = v.Type_expr.Search_fun(name, CASE_SEN | ONLY_METHODS,
               TRUE)
    ;
    CASE ffun == NONE ?
         {Type} s_cl|ass_seach_in = v.Type_expr
         CASE s_cl.Kind == 'STRUCTURE' ? s_cl = s_cl.In_class_ ;
         ffun = s_cl.Search_fun(name, CASE_SEN | IMPORTED_CL, TRUE)
         CASE ffun.Overload_base_!=NONE ? ffun= ffun.Overload_base_ ;
         CASE ffun != NONE && ffun.Overloaded_[].Count > 0
              && ffun.Overloaded_differ_by_first_param
              ?
              FOR fn IN ffun.Overloaded_[] :
                  CASE ?
                  [v.Type_expr == fn.First_param_type] ? NONE

                  [v.Type_expr.Kind != 'CLASS'] ? CONTINUE fn

                  [v.Type_expr.Is_descend(
                    fn.First_param_type, comp(Parse))] ? NONE

                  ELSE CONTINUE fn ;
                  DONE
                       ffun = fn
                       CASE fn !IN cf.Call_functions_[] ?
                            cf.Call_functions_[] << fn ;
                       BREAK fn ;
         ;
    ;
    CASE ffun == NONE ?
        Parse.Pos = pos
        RESULT = chain_fun_of_val(v, Parse) ==> ;
    ------------------------------------ 'v.fun(...) or fun(v, ...)'
    CASE ?
    [ffun.Modifiers['STATIC'] && ffun.Param[].Count == 0] ?
         Parse.Err("Static function has no parameters"._ENoParameters
         ": " ffun.Whole_name)
    [ffun.Modifiers['STATIC']] ?
         CASE ?
         [ffun.Param[0].Type_.Kind == 'CLASS' && (
          v.Type_expr.Kind != 'CLASS')] ?
              Parse.Err("Static function first parameter is an object "
              "but the prefix expression is not an object"._ENotObject
              ": " ffun.Whole_name)

         [ffun.Param[0].Type_.Kind == 'CLASS'
          && v.Type_expr.Kind == 'CLASS'] ?
                CASE !v.Type_expr.Is_descend(
                     ffun.Param[0].Type_, comp(Parse))
                     ?
                     Parse.Err("Static function first parameter is not "
                     "compatible with the prefix object type"
                     ""._ENotCompat ": " ffun.Whole_name)
                ;
         ;
    [v.Type_expr.Kind != 'CLASS'] ?
         Parse.Err("Calling method of object but the prefix expression "
         "is not an object"._ECallingMethod
         ": " ffun.Whole_name)

    [!v.Type_expr.Is_descend(ffun.Class, comp(Parse))] ?
         Parse.Err("Method is from class which is not compatible with "
         "the prefix object"._EFromClass
         ": " ffun.Whole_name) ;
    ------------------------------------ 'if class of fun is imported?'
    CASE !ffun.Is_public && !cc.Is_descend(ffun.Class, comp(Parse))
         && cc.Names[0] !IN ffun.Class.Friends[]
         ?
         STR er|ror_message = "Calling non-public function of the "
             "non-familiar class"._Ecalling ": " ffun.Class.Whole_name

         er = er "." ffun.Whole_name
         Parse.Err(er)
    ;
    CASE ffun.Class != NONE && "{}" !IN ffun.Class.Names[] && (
         ffun.Class != cc) && (
         ffun.Class !IN cc.Import_[]) && (
         ffun.Class !IN cc.Debug_import_[]) && !(
         comp(Parse).Current_fun.Is_test && (
         ffun.Class IN cc.Test_import_[]))
         ?
         er = "Function"._Efun5 " " ffun.Whole_name " "

         er = er "" ("is from class"._Eisfrom) ffun.Class.Whole_name
              "" ("which is not imported"._Ewhich)

         Parse.Err(er)
    ELSE
         CASE ffun.Class != cc && ffun.Class !IN cc.Used_imports_[] ?
              cc.Used_imports_[] << ffun.Class ;
    ;
    RESULT = Operation_call_fun(ffun, v, Parse) .
        */
        static int CNT_chain_field = 0;

        private static Expression chain_field_or_fun(Expression V, Parser Parse)
        {
            if (CNT_chain_field++ == 11484)
            { }

            Expression Result = V;
            if (V.Type_expr() != null && V.Type_expr().Kind != Type.Kind_type.CLASS)
            {
                Result = chain_fun_of_val(V, Parse);
                return Result;
            }
            int pos = Parse.Pos;
            Parse.Wait(".");
            if (Parse.Next_symbol("{"))
            {
                if (V.Is_array() || V.Type_expr() != null && V.Type_expr().Kind != Type.Kind_type.CLASS)
                    Parse.Err("Typecast operation is not applicable: " +
                        Parse.Next20());
                Result = new Expression();
                Result.Operation = Operation_kind.AS;
                Result.Arg1_ = V;
                Result.Type_obj_ = Parse.Compiler_.Current_class.Find_type(
                    Parse.Scan_type());
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                if (Result.Type_expr() != null && Result.Type_expr().Kind != Type.Kind_type.CLASS)
                    Parse.Err("Typecast not to class type: " + Result.Type_obj_.Name());
                if (Result.Type_expr() != null && 
                    !Result.Type_expr().Is_descendant_of(V.Type_expr(), Parse.Compiler_) &&
                    V.Type_expr() != null && 
                    !V.Type_expr().Is_descendant_of(Result.Type_expr(), Parse.Compiler_))
                    Parse.Err("Typecast not to inherited or descendant " +
                        "class: " + V.Type_expr().Name() + " -> " + Result.Type_expr().Name());
                return Result;
            }
            string name = Parse.Ident();
            //----------------------------- 'field'
            Variable f = V.Type_expr() == null ? null : V.Type_expr().Search_field(name);
            if (f != null)
            {
                Result = new Expression();
                Result.Operation = Operation_kind.FIELD;
                Result.Arg1_ = V;
                Result.Var_arg = f;
                Result.At_line = Parse.Line;
                Result.At_pos = pos;
                return Result;
            }
            //------------------------------ 'function'
            Function fun = V.Type_expr() == null ? null : V.Type_expr().Search_fun(name, false);
            if (fun == null)
            {
                Parse.Pos = pos;
                return chain_fun_of_val(V, Parse);
            }
            Result = Operation_call_fun(fun, V, Parse);
            return Result;
        }

        /*
        
        BOOL For_loop_var|iable_replacement_for_loop_in_STRUCTures_array
        BOOL Is_index|_of_loop_variable_in_FOR_STRUCT
        
        FUNCTION chain_fun_of_val({Expr} Value|_as_obj,
            {Parser} Parse|_src) ==> {Expr}, NEW
            :
            ------------------------------------- '.Fun(... or .Special_fun(...'
            Parse.Wait(".")
            BOOL is_not|_operation = Parse.Symbol("!")
            STR name|_of_fun = Parse.Ident
            {Fun} cf|unction_currently_compiling = comp(Parse).Current_fun
            {Expr} v|alue_based_on = Value
            
            PUSH cf.Count_not :
            	 CASE is_not ? 
            	      CASE cf.Count_not > 0 ? 
            	           Parse.Err("Suspicious sequentional '!' operations "
            	           "applied to the same operand"._ESupectNot2) 
            	      ;
            	      cf.Count_not += 1
            	 ;
                 {Expr} temp|_result = chain_fun_of_val_1(
                 	v, Parse, name)
                 	
                 CASE is_not ?
                 	  CASE temp.Operation !IN ['FUN', 'SYSTEM_FUN', 'BASE_FUN']
                 	       || temp.Type_expr.Kind != 'BOOL'
                 	       ? 
                 	       Parse.Err("Operation '!' is not applicable"
                 	       ""._ENotNotApplicable) ;
                      {Expr} temp_was = temp
                      temp = {Expr}(Operation = 'NOT', Arg1_= temp_was)
                 ;
                 RESULT = temp
            ; .
            
        FUNCTION chain_fun_of_val_1(
        {Expr} v|alue_as_object,
        {Parser} Parse|_src, STR name|_of_fun) ==> {Expr}, NEW
            :
	        {Fun} cf|unction_currently_compiling = comp(Parse).Current_fun
	        INT at_pos|ition = Parse.Pos

            CASE ?
            [v.Is_array] ?
                 {Fun} f|unction_calling = array_function(v, Parse, name)
                 CASE f == comp(Parse).SYSFUN_Delete 
                 	  || f == comp(Parse).SYSFUN_Remove
                 	  ?
                      comp(Parse).Current_fun.Is_deleting_obj = TRUE ;
                 CASE f.System_fun IN ['SYSFUN_Insert', 'SYSFUN_Remove', 
                      'SYSFUN_Delete', 'SYSFUN_Clear', 'SYSFUN_Allocate']
                      ? 
                      v.Var_arg.Has_changing_size = TRUE ;
                 
            [v.Type_expr.Kind == 'CLASS'] ?
                 INT flags|_search = ONLY_METHODS
                 CASE !cf.Parse.Case_insensitive ? flags |= CASE_SEN ;
                 f = v.Type_expr.Search_fun(name, flags, TRUE)
                 //CASE f == NONE ? 
                 //     {Var} w|_field_of_class = v.Type_expr.Search_field(name) 
                 //     CASE w != NONE ? 
                 //          RESULT = {Expr}(Operation= 'FIELD',
                 //           Arg1_= v, Var_arg= w) ==> ;
                 //;
                 
            [v.Type_expr.Kind == 'STRUCTURE'] ?
                 flags = ONLY_ST
                 CASE !cf.Parse.Case_insensitive ? flags |= CASE_SEN ;
                 f = v.Type_expr.In_class_.Search_fun(name, flags, TRUE)
                 CASE f.Param[0].Type_ != v.Type_expr ? f = NONE ;
                 BOOL do_check_compat = f != NONE          
            ;
            ----------------------- 'system scalar functions'
            CASE f == NONE ?
            	 f = scalar_function(v, Parse, name) ;
            CASE f == NONE ? 
                 CASE name.Upper == "INDEX" && v.Operation == 'INDEX' ? 
                      RESULT = {Expr}(Operation= 'VAR', 
                      	Var_arg= v.Arg2_.Var_arg,
                      	Is_index= TRUE), 
                      	>> cf.All_expr[] ==> ; 
                 flags = ONLY_ST|IMPORTED_CL
                 CASE !cf.Parse.Case_insensitive ? flags |= CASE_SEN ;
            	 f = comp(Parse).Current_class.Search_fun(name, flags, TRUE)
            	 do_check_compat = f != NONE
            ;
            ---------------------------------------- 'f should be defined here'
            CASE f == NONE ?
                 CASE ?
	             [name.[0] == "_"] ?
	                  --------------------------------- 'string._name'
	                  make_localizable(v, name.[1 TO *], Parse)
	                  RESULT = v ==>
	             [v.Type_expr.Kind == 'CLASS'] ?
	                  --------------------------------- 'objVar.Some_method(...'
	                  flags = IMPORTED_CL
	                  CASE !cf.Parse.Case_insensitive ? flags |= CASE_SEN ;
	                  f = v.Type_expr.Search_fun(name, flags, TRUE)
	                  do_check_compat = f != NONE
	             ;
	                  
	             CASE f == NONE ?
	                  --------------------------------- 'param1.Some_fun(...'
	                  PUSH Parse.Pos = at_pos :
	                       f = comp(Parse).Current_class.Find_fun_of_val(name)
	                  ;
	                  do_check_compat = f != NONE 
	             ;
	                  
	             CASE f == NONE ?
                 	  Parse.Err("Undefined function"._Eundef ": " name) ==> 
	             ;
            ;
            v.Is_param = TRUE
            
            RESULT = {Expr}(Operation = 'FUN', Fun_ = f,
                 At_line = Parse.Line, At_pos = at_pos)
                 
            CASE f.Modifiers['STATIC'] ? 
                 RESULT.Items_[] << v
            	 CASE ?
            	 [!f.Param[0].Is_fixed] ?
            	 	  CASE v.Is_fixed ?
            	      Parse.Err("Applying method intended for a dynamic array "
            	      "to the fixed array"._EFix2Dyn) ;
            	 [f.Param[0].Is_fixed && !f.Is_system] ?
            	     CASE !v.Is_fixed ? 
            	          Parse.Warn("Applying method intended for a fixed "
            	          "array to the dynamic array (it is necessary to "
            	          "specify a range X TO Y to pass a fixed array)"
            	          ""._WDyn2Fix) ;
            	 ;
            ELSE RESULT.This_ = v
            ;
                 
            CASE f.Overloaded_[].Count > 0 && f.Param[].Count == 1 ?
                 cf.Call_functions_[].Remove(f)
                 f = find_matching_overloaded(RESULT, Parse)
                 CASE f !IN cf.Call_functions_[] ?
                 	  cf.Call_functions_[] << f ; 
            ;
            CASE f != NONE && do_check_compat ?
                 left|temp = {Expr}(Operation = 'VAR',
                     Var_arg = f.Param[0], At_line = Parse.Line,
                     At_pos = at_pos)
                     
                 BOOL a|pplicable_to_V = TRUE
                 CASE !cf.Dummy_compile && f.Overloaded_[].Count == 0 ?
                      PUSH comp(Parse).Error_prefix = "(" (
                           "While calling function"._EWhileCalling)
                           " " f.Names[0] ")" :
                           cf.Assign_check_compat(left, v) ;
                 ;
            ;
            --------------------- 'for Clone/Dismiss fix RESULT type:'
            CASE f == comp(Parse).SYSFUN_Clone
            	 || f == comp(Parse).SYSFUN_Dismiss
            	 ?
                 RESULT.Type_obj_ = v.Type_expr ;
            
            CASE ?
            [f.Is_system] ?
                 a = v.system_function_param(f, Parse, RESULT)
                 CASE RESULT.Operation == 'CONST' ? ==> ; 
                 CASE f.System_fun IN ['SYSFUN_Insert', 'SYSFUN_Delete',
                      'SYSFUN_Clear', 'SYSFUN_Allocate', 'SYSFUN_Remove']
                      ?
                      v.Var_arg.Has_changing_size = TRUE ;
            [!f.Modifiers['STATIC']] ? a = TRUE 
            ;
            CASE !a ? Parse.Err(name " " ("is not applicable"._Eisnot4 ) ) ;                 
            
            cf.Last_fun_ = f
            f.Count_ref += 1
            ------------------------------------- 'if params already prepared:'
            CASE f.Is_system ? 
                 RESULT.Operation = 'SYSTEM_FUN' ==> ;
            ---------------------------------------- 'parameters'
            CASE f.Modifiers['STATIC'] && f.Param[].Count > 1
            	 || !f.Modifiers['STATIC'] && f.Param[].Count > 0
            	 ?
                 Parse.Wait("(")
                 INT k|_waiting_brackets = brackets_to_wait(Parse)
                 PUSH cf.Left_side = FALSE :
	                  CASE f.Modifiers['STATIC'] ?
	                       INT param1|_index = 1
	                  ELSE param1 = 0 ;
	                  FOR i IN [param1 TO f.Param[].Count-1] :
	                      INT was_at|_position = Parse.Pos
	                      
	                      {Expr} param|eter_next = Recognize(Parse),
	                      		 >> cf.All_expr[]
	                      ----------------------- 'convert INT to REAL ?'		 
	                      BOOL op_i2r|eal = !param.Is_array
	                     	   op_i2r &&= param.Type_expr.Kind == 'INT'
	                     	   op_i2r &&= f.Param[i].Type_.Kind == 'REAL' 
	                      CASE op_i2r ?
	                           {Expr} int_param = param
	                           
	                           param = {Expr}(Operation = 'INT2REAL',
	                          		   Arg1_ = int_param,
	                          		   Is_param = TRUE,
	                          		   Type_obj_ = comp(Parse).TYPE_REAL),
	                          		   >> cf.All_expr[] 
	                      ;
	                      RESULT.Items_[] << param
	                      -------------- 'check parameter compatibility'
	                      {kind_type} kind_p|arameter = param.Type_expr.Kind
	                      CASE f.Param[i].Type_ != NONE
	                     	   && f.Param[i].Type_ != param.Type_expr
	                     	   && !(f.Param[i].Type_.Kind == 'CLASS'
	                                || f.Param[i].Type_.Kind == 'REAL'
	                                && kind_p == 'INT')
	                     	   ?
	                           PUSH Parse.Pos = was_at :
	                          	 Parse.Err("Incompatible parameter type"
	                          	 ""._EIncompat2 ": " Parse.Next20) ;
	                      ;
	                      
	                      dest|ination_temp = {Expr}(Operation = 'VAR', 
	                         Var_arg = f.Param[i])
	                         
	                      CASE f.Overloaded_[].Count == 0 ?
	                     	   cf.Assign_check_compat(dest, param) ;
	                      CASE i < f.Param[].Count-1 ? 
	                           Parse.Wait_det(",", "Incorrect amount of "
	                           "parameters, waiting parameter"
	                           ""._EIncorrectAmountParam 
	                           ": " f.Param[i+1].Whole_name
	                           " (" ("of type"._EOf_type)
	                           ": " f.Param[i+1].Type_.Names[0] ")") ;
	                  ;
                 ;
                 FOR i IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait(")")
	             CASE f.Overloaded_[].Count > 0 ?
	                  f = find_matching_overloaded(RESULT, Parse)
	             ;
	             CASE f.Overloaded_[].Count > 0 ?
	                  STR e|rror_text = f.Class.Whole_name
	                  e = e "." f.Whole_name
	                  Parse.Err("Ambiguous overloaded function call? (" e ")") ;
            ELSE Parse.Skip_sp
                 CASE Parse.Next_char == "(" ?
                    CASE f.Result.Type_.Kind == 'STR' ?
                      Parse.Err("Symbol '(' should not follow the function call"
                      " if the function returns STR result and has no explicit "
                      "parameters"._Esymbol2) ;

                 ;
            ; .
            
        METHOD system_function_param(
        {Fun} System_f|unction,
        {Parser} Parse|_source,
        {Expr} Call|_function_result_expr) ==> BOOL
        	:
        	{Expr} v|alue_param0 = THIS
        	{Fun} cf|unction_currently_compiling = comp(Parse).Current_fun
        	
            CASE System_f.System_fun ?
            ['SYSFUN_Count']:
                ------------------------------- 'a[].Count'
                CASE v.Is_fixed && !v.Is_temp_fixed && (
                	 !v.Var_arg.Is_param) && (
                     v.Var_arg.Size_n != "*")
                     ?
                     CASE v.Var_arg == NONE ?
                          Parse.Err("-- internal-- "
                          "Fixed array w/o variable"._Einternal3 )
                     ;
                     INT val|ue_constant = v.Var_arg.Size_value
                     ------------ 'translate * to constant when fixed array'
                     Call.Operation = 'CONST'
                     Call.Fun_ = NONE
                     
                     Call.Var_arg = {Var}(
                        Line = -1,
                        Is_const= TRUE,
                        Type_ = comp(Parse).TYPE_INT,
                        Int_c = val) 
                        
                     RESULT = TRUE ==> 
                ;
                        
				BOOL a|pplicable = v.Is_array
            ['SYSFUN_Clear']:
                ------------------------------- 'a[].Clear'
                a = v.Is_array
            ['SYSFUN_Insert']:
                ------------------------------ 'a[].Insert(where, what)'
                cf.Has_add = TRUE
                Parse.Wait("(")
                INT k|_waiting_brackets = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     {Expr} param|_in_brackets = Recognize_typed(Parse, 'INT'),
                             >> cf.All_expr[]
                             
                     Parse.Wait(",")
                     
                     {Expr} param2|_in_brackets = Recognize(Parse),
                             >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                ---------------------- 'check parameters of Insert'
                a = v.Is_array 
                a &&= ! param2.Is_array
                CASE param2.Is_array ?
                     not_applicable(Parse,
                     "Inserting value is not a scalar"._Enotscalar)
                ;
                cf.Append_check_compat(v, param2, "Insert")
            ['SYSFUN_Delete', 'SYSFUN_Allocate']:
                ------------------ 'a[].Delete(where), a[].Allocate(New_size)'
                a = v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize_typed(Parse, 'INT'),
                         >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                a &&= ! param.Is_array
                
            ['SYSFUN_Remove']:
                ----------------------------- 'a[].Remove(what)'
                a = v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize(Parse),
                     >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                CASE ! cf.Check_compat(v, param)?
                    Parse.Err("Invalid parameter for Remove"._Einvalid3 )
                ;
                a &&= ! param.Is_array
                CASE !a ?
                     not_applicable(Parse,
                     "Removing value is not a scalar"._Eremovingnotscalar)
                ;
            ['SYSFUN_Swap']:
                ----------------------------- 'a[].Swapt(i, j)'
                a = v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize_typed(Parse, 'INT'), >> cf.All_expr[]
                     Parse.Wait(",")
                     param2 = Recognize_typed(Parse, 'INT'), >> cf.All_expr[] 
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                a &&= ! param.Is_array
                a &&= ! param2.Is_array
			['SYSFUN_Index']:
                ------------------------------- 'loopVar.Index'
                a = v.Var_arg.Is_loop
            ['SYSFUN_Len']:
                ------------------------------- 'strVar.Len'
                a = v.Type_expr.Kind == 'STR' 
                a &&= ! v.Is_array
                CASE !a ?
                     not_applicable(Parse,
                     "Subject is not a string"._Enotstrarr)
                ;
            ['SYSFUN_Name']:
                ------------------------------- 'enumItem.Name'
                a = v.Type_expr.Kind IN ['ENUM', 'BOOL']
                CASE !a ?
                     not_applicable(Parse,
                     "Subject is not an enumeration"._Enotenum)
                ;
            ['SYSFUN_Find_str']:
                ------------------------------ '.Find(...)'
                a = !v.Is_array
                a &&= v.Type_expr.Kind == 'STR'
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize_typed(Parse, 'STR'), >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
            ['SYSFUN_Find_item']:
                ------------------------------ '.Find(...)'
                a = v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize(Parse), >> cf.All_expr[]
                            
                     x_param|eter = {Expr}(Operation = 'VAR',
                            Var_arg = System_f.Param[0]),
                            >> cf.All_expr[]
                            
                     x_param.Var_arg.Type_ = v.Type_expr
                     cf.Append_check_compat(x_param, param, "")
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
            ['SYSFUN_Str']:
                ----------------------------- 'x.Str'
                a = v.Type_expr.Kind == 'INT'
                a &&= ! v.Is_array
                    
            ['SYSFUN_BoolStr']:
                ----------------------------- 'x.Str'
                a = v.Type_expr.Kind == 'BOOL' 
                a &&= ! v.Is_array
                    
            ['SYSFUN_RealStr']:
                ----------------------------- 'r.Str'
                a = v.Type_expr.Kind == 'REAL'
                a &&= ! v.Is_array
                    
            ['SYSFUN_RealInt']:
                ----------------------------- 'r.Int'
                a = v.Type_expr.Kind == 'REAL'
                a &&= ! v.Is_array
                    
            ['SYSFUN_StrInt']:
                ----------------------------- 's.Int'
                a = v.Type_expr.Kind == 'STR'
                a &&= ! v.Is_array
                
            ['SYSFUN_Byte']:
                ----------------------------- 'i.Byte'
                a = v.Type_expr.Kind == 'INT'
                a &&= ! v.Is_array

            ['SYSFUN_StrHex16']:
                ----------------------------- 'i.Hex(d)'
                a = v.Type_expr.Kind == 'INT'
                a &&= ! v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize_typed(Parse, 'INT'), >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                
            ['SYSFUN_EnumInt']:
                ----------------------------- 'enum.Int'
                a = v.Type_expr.Kind == 'ENUM' 
                a &&= ! v.Is_array
                
            ['SYSFUN_Shl', 'SYSFUN_Shr', 'SYSFUN_Rol', 'SYSFUN_Ror']:
                ----------------------------- 'intVar.ShiftL(how_many_bits)'
                a = v.Type_expr.Kind == 'INT'
                a &&= ! v.Is_array
                Parse.Wait("(")
                k = brackets_to_wait(Parse)
                PUSH cf.Left_side = FALSE :
                     param = Recognize_typed(Parse, 'INT'), >> cf.All_expr[]
                ;
                FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                Parse.Wait(")")
                a &&= ! param.Is_array
                
            ['SYSFUN_First', 'SYSFUN_Next', 'SYSFUN_Last', 'SYSFUN_Previous']:
                a = v.Type_expr.Kind == 'ENUM'
                a &&= !v.Is_array
              
            ['SYSFUN_Clone', 'SYSFUN_Dismiss']:
                a = v.Type_expr.Kind == 'STRUCTURE'
                a &&= !v.Is_array
              
            ['SYSFUN_Compare_substrings', 'SYSFUN_Compare_substr1']:
             	a = TRUE
            	NONE // called internally only
            	
            ['SYSFUN_UNDEFINED']:
            	Parse.Err("Undefined system function")
            ; 
            CASE param != NONE ? Call.Items_[] << param
            					 param.Is_param = TRUE 
            ;
            CASE param2 != NONE ? Call.Items_[] << param2
            					  param2.Is_param = TRUE 
            ; 
            RESULT = a .
                     
            
		FUNCTION array_function(
			{Expr} V|alue_to_apply_function_to_DUMMY,
			{Parser} Parse|_of_source,
			STR Name|_system_function) ==> {Fun}
			:
			CASE Parse.Case_insensitive ?
			     STR name|_canonical = Name.[0].Upper Name.[1 TO *].Lower
			ELSE name = Name ;
			CASE name ?
            ["Clear", "CLEAR"]:
				{Fun} f|unction_defined = comp(Parse).SYSFUN_Clear
            ["Count", "COUNT"]: f = comp(Parse).SYSFUN_Count
            ["Find", "FIND"]: f = comp(Parse).SYSFUN_Find_item
            ["Insert", "INSERT"]: f = comp(Parse).SYSFUN_Insert
            ["Allocate", "ALLOCATE"]: f = comp(Parse).SYSFUN_Allocate
            ["Delete", "DELETE"]: f = comp(Parse).SYSFUN_Delete
            ["Remove", "REMOVE"]: f = comp(Parse).SYSFUN_Remove
            ["Swap", "SWAP"]: f = comp(Parse).SYSFUN_Swap
			; 
			RESULT = f .
			
  
		FUNCTION scalar_function(
			{Expr} V|alue_to_apply_function_to,
			{Parser} Parse|_of_source, STR Name|_of_function) ==> {Fun}
			:
			CASE Parse.Case_insensitive ?
			     STR name|_canonical = Name.Upper
			ELSE name = Name ;
			CASE name ?
            ["Index", "INDEX"]:
				{Fun} f|unction_calling = comp(Parse).SYSFUN_Index
				CASE ?
				[V.Operation == 'INDEX' && V.For_loop_var] ? ==>
				[!V.Var_arg.Is_loop] ?
				     Parse.Err("Index is not applicable, variable is not a loop"
				     " variable"._EIndexNotApp1 
				     ": " V.Var_arg.Whole_name)
				[V.Var_arg.For_.Array == NONE]
				 ?
				     Parse.Err("Index is not applicable, variable is not an "
				     "array items enumerator"._EIndexNotApp2
				     ": " V.Var_arg.Whole_name)
				;
            ["Len", "Length", "LEN", "LENGTH"]: f = comp(Parse).SYSFUN_Len
            ["Name", "NAME"]: f = comp(Parse).SYSFUN_Name
            ["Find", "FIND"]: f = comp(Parse).SYSFUN_Find_str
            ["Str", "S", "STR", "STRING"]:
                CASE V.Type_expr.Kind ?
                ['BOOL']: f = comp(Parse).SYSFUN_BoolStr
                ['INT']: f = comp(Parse).SYSFUN_Str
                ['REAL']: f = comp(Parse).SYSFUN_RealStr
                ['ENUM', 'CLASS', 'STRUCTURE', 'STR']:
            		Parse.Err("Str is not applicable to data type of "
                         "kind"._Estr " " V.Type_expr.Kind.Name)
                ;
            ["Int", "Integer", "INT", "INTEGER"]:
                ----------------------------- 'functions x.Int'
                CASE V.Type_expr.Kind ?
                ['STR']: f = comp(Parse).SYSFUN_StrInt
                ['REAL']: f = comp(Parse).SYSFUN_RealInt
                ['ENUM']: f = comp(Parse).SYSFUN_EnumInt
                
                ['BOOL', 'INT', 'CLASS', 'STRUCTURE']:
					Parse.Err("Invalid Int cast"._Einvalid4 )
                ;
            ["Byte"]:
                CASE V.Type_expr.Kind != 'INT' ? 
                     Parse.Err("Byte is applicable onty to INT data type "
                     "values"._EByteToINTOnly) ;
                f = comp(Parse).SYSFUN_Byte
                
            ["ShiftL", "ShiftLeft", "Shift_left",
             "ShiftR", "ShiftRight", "Shift_right",
             "RotateL", "RotateLeft", "Rotate_left",
             "RotateR", "RotateRight", "Rotate_right",
             "SHIFTL", "SHIFTLEFT", "SHIFT_LEFT",
             "SHIFTR", "SHIFTRIGHT", "SHIFT_RIGHT",
             "ROTATEL", "ROTATELEFT", "ROTATE_LEFT",
             "ROTATER", "ROTATERIGHT", "ROTATE_RIGHT"]:
                ----------------------------- 'intVar.ShiftL(how_many_bits)'
                CASE Name.Upper ?
                ["SHIFTL", "SHIFTLEFT", "SHIFT_LEFT"]:
					f = comp(Parse).SYSFUN_Shl
                ["SHIFTR", "SHIFTRIGHT", "SHIFT_RIGHT"]:
					f = comp(Parse).SYSFUN_Shr
                ["ROTATEL", "ROTATELEFT", "ROTATE_LEFT"]:
					f = comp(Parse).SYSFUN_Rol
                ["ROTATER", "ROTATERIGHT", "ROTATE_RIGHT"]:
					f = comp(Parse).SYSFUN_Ror
                
                ELSE
                	 Parse.Err(
                     	  "Internal error -- function not found"._Einternal4
                     	  ": " Name)
                ;
            ["Next", "Prev", "Previous", "First", "Last",
             "NEXT", "PREV", "PREVIOUS", "FIRST", "LAST"]:
                
				CASE Name ?
				["Next"]: f = comp(Parse).SYSFUN_Next
				["Prev", "Previous"]: f = comp(Parse).SYSFUN_Previous
				["First"]: f = comp(Parse).SYSFUN_First
				["Last"]: f = comp(Parse).SYSFUN_Last ;
            ["Clone", "CLONE"]:
				CASE V.Type_expr.Kind == 'STRUCTURE' ?
				     f = comp(Parse).SYSFUN_Clone ;
            ["Dismiss", "DISMISS"]:
				CASE V.Type_expr.Kind == 'STRUCTURE' ?
				     f = comp(Parse).SYSFUN_Dismiss ;
            ;
        	RESULT = f .
        
	

            
   		FUNCTION not_applicable(
   			{Parser} Parse|_to_message, STR Text|_message)
   			:
			Parse.Err("Not applicable"._Enotapplicable ". " Text) .
                 
        FUN make_localizable({Expr} V|alue_string_constant,
            STR Name|_of_string, {Parser} Parse|_src)
            :
            CASE comp(Parse).Compiling_LIKE ? ==> ;
            {Type} cc|urrent_class = comp(Parse).Current_class
            FOR im IN cc.Import_[] :
                CASE "{Localize_str}" == im.Names[0] ?
                     BOOL found|_class_localize_str = TRUE
                     CASE im !IN cc.Used_imports_[] ?
                          cc.Used_imports_[] << im ;
                     BREAK im ;
            ;
            CASE !found ?
                 Parse.Err("To use localized strings, the class {Localize_str} "
                 "should be imported (and method Localize called)."._Eto )
            ;
            -------------------------------- 'check if it is a constant string'
            {Type} type_v|alue = V.Type_expr
            BOOL is_const_s|tring = type_v.Kind == 'STR'
            	 is_const_s &&= V.Is_constant_expr
            	 is_const_s &&= !V.Is_array
            CASE !is_const_s ?
                 Parse.Err("_Localization is not applicable (not a scalar "
                 "constant string):"._Eloc " " type_v.Kind.Name)
            ;
            ----------------- 'check duplicating name for localization string'
            CASE Name IN cc.Localize_n[] ?
                 Parse.Err("Duplicating string name"._Edup ": " Name 
                 " (earlier defined in line "
                 "" (cc.Localize_line[cc.Localize_n[].Find(Name)]+1).Str ")")
            ;
            CASE V.has_CR_LF(Parse) ?
                 Parse.Err("_Localization is not applicable for a string "
                 "containing symbols #CR/#LF"._Eloc2 )
            ;
            ----------------------- 'add to localization strings'
            cc.Localize_n[] << Name
            cc.Localize_s[] << V
            cc.Localize_line[] << Parse.Line
            V.Localize_n = Name 
            V.Localize_i = cc.Localize_n[].Count-1 .
            
        METHOD has_CR_LF(
        {Parser} Parse|_in_context) ==> BOOL, RECURSIVE
        	:
            CASE Operation == 'CONSTANT' ?
                 RESULT = #CR IN Var_arg.Str_c || #LF IN Var_arg.Str_c ==> ;
            CASE !( Operation == 'BINARY' && Sign == 'CONCAT') ?
                 Parse.Err("Can not check if CR/LF are in a string "
                 "constant"._Ecannot2 )
            ;
            RESULT = Arg1_.has_CR_LF(Parse)
            RESULT ||= Arg2_.has_CR_LF(Parse) .
                 
        */
        static int CNT_chain_fun_of_val;
        private static Expression chain_fun_of_val(Expression V, Parser Parse)
        {
            if (++CNT_chain_fun_of_val == 345)
            { }
            
            Parse.Wait(".");
            int at_pos = Parse.Pos;
            string name = Parse.Ident();
            bool sw_ok = false;
            bool a = false;
            Function f = null;
            Expression param = null;
            Expression param2 = null;
            switch ((name + (char)0)[0])
            {
                case 'I':
                    if (name == "Index")
                    {
                        sw_ok = true;
                        a = V.Var_arg != null && V.Var_arg.Is_loop_var;
                        f = Parse.Compiler_.SYSFUN_Index;
                    }
                    else if (name == "Insert")
                    {
                        sw_ok = true;
                        Parse.Compiler_.Current_fun.Has_add = true;
                        f = Parse.Compiler_.SYSFUN_Insert;
                        Parse.Wait("(");
                        param = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                        Parse.Wait(",");
                        param2 = Expression.Recognize(Parse);
                        Parse.Wait(")");
                        a = V.Is_array() && !param.Is_array() && !param2.Is_array();
                        Parse.Compiler_.Current_fun.Check_compat(V, param2);
                    }
                    break;
                case 'L':
                    if (name == "Len" || name == "Length")
                    {
                        sw_ok = true;
                        a = V.Type_expr().Kind == Type.Kind_type.STR && !V.Is_array();
                        f = Parse.Compiler_.SYSFUN_Len;
                    }
                    break;
                case 'C':
                    if (name == "Count")
                    {
                        sw_ok = true;
                        a = V.Is_array();
                        f = Parse.Compiler_.SYSFUN_Count;
                    }
                    else if (name == "Clear")
                    {
                        sw_ok = true;
                        a = V.Is_array();
                        f = Parse.Compiler_.SYSFUN_Clear;
                    }
                    break;
                case 'N':
                    if (name == "Name")
                    {
                        sw_ok = true;
                        a = V.Type_expr().Kind == Type.Kind_type.ENUM;
                        f = Parse.Compiler_.SYSFUN_Name;
                    }
                    break;
                case 'D':
                    if (name == "Delete")
                    {
                        sw_ok = true;
                        a = V.Is_array() && !V.Is_fixed();
                        f = Parse.Compiler_.SYSFUN_Delete;
                        Parse.Wait("(");
                        param = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                        Parse.Wait(")");
                        a = a && !param.Is_array();
                    }
                    break;
                case 'R':
                    if (name == "Remove")
                    {
                        sw_ok = true;
                        a = V.Is_array() && !V.Is_fixed();
                        f = Parse.Compiler_.SYSFUN_Remove;
                        Parse.Wait("(");
                        param = Expression.Recognize(Parse);
                        Parse.Wait(")");
                        a = a && !param.Is_array();
                        if (!Parse.Compiler_.Current_fun.Check_compat(V, param))
                            Parse.Err("Invalid parameter for Remove");
                    }
                    break;
                case 'S':
                    if (name == "Str")
                    {
                        sw_ok = true;
                        a = V.Type_expr().Kind == Type.Kind_type.INT || 
                            V.Type_expr().Kind == Type.Kind_type.REAL;
                        a = a && !V.Is_array();
                        f = Parse.Compiler_.SYSFUN_Str;
                        if (V.Type_expr().Kind == Type.Kind_type.REAL)
                            f = Parse.Compiler_.SYSFUN_RealStr;
                    }
                    break;
                case 'F':
                    if (name == "Find")
                    {
                        sw_ok = true;
                        a = V.Type_expr().Kind == Type.Kind_type.STR || V.Is_array();
                        if (V.Is_array()) f = Parse.Compiler_.SYSFUN_Find_item;
                        else f = Parse.Compiler_.SYSFUN_Find_str;
                        Parse.Wait("(");
                        if (V.Is_array())
                        {
                            param = Expression.Recognize(Parse);
                            Expression dst_param = new Expression();
                            dst_param.Operation = Operation_kind.VAR;
                            dst_param.Var_arg = f.Param[0];
                            dst_param.Var_arg.Type_ = V.Type_expr();
                            Parse.Compiler_.Current_fun.Assign_check_compat(
                                dst_param, param, at_pos);
                        }
                        else param = Expression.Recognize_typed(Parse, Type.Kind_type.STR);
                        Parse.Wait(")");
                    }
                    break;
            }
            if (!sw_ok)
            {
                if (name[0] == '_') return V;
                if (V.Type_expr() != null && V.Type_expr().Kind == Type.Kind_type.CLASS)
                    f = V.Type_expr().Search_fun(name, false);
                if (f == null)
                    f = Parse.Compiler_.Current_class.Find_fun_of_val(name);
                if (f != null)
                {
                    int at = Parse.Pos;
                    Expression left = new Expression();
                    left.Operation = Operation_kind.VAR;
                    left.Var_arg = f.Param[0];
                    left.At_line = Parse.Line;
                    left.At_pos = at_pos;
                    Parse.Compiler_.Current_fun.Assign_check_compat(left, V, at_pos);
                    a = true;
                }
            }
            if (f == null)
            {
                Parse.Err("Undefined function: " + name);
                return V;
            }
            if (!a) Parse.Err(name + " is not applicable");
            Expression Result = new Expression();
            Result.Operation = Operation_kind.FUN;
            Result.Fun_ = f;
            Result.Items_.Add(V);
            Result.At_line = Parse.Line;
            Result.At_pos = at_pos;
            if (param != null)
                Result.Items_.Add(param);
            if (param2 != null)
                Result.Items_.Add(param2);
            return Result;
        }

        private static void apply_inc_dec(Expression E, Parser Parse)
        {
            switch ((Parse.Next_char() + (char)0)[0])
            {
                case '+':
                    if (Parse.Symbol("++"))
                    {
                        E.Inc = true; return;
                    }
                    break;
                case '-':
                    if (Parse.Symbol("--"))
                    {
                        E.Dec = true;
                    }
                    break;
            }
            if (!E.Inc && !E.Dec) return;
            bool not_a = false;
            Variable v = null;
            switch (E.Operation)
            {
                case Operation_kind.VAR:
                case Operation_kind.FIELD:
                    v = E.Var_arg;
                    break;
                case Operation_kind.INDEX:
                    v = E.Arg1_.Var_arg;
                    break;
                default: not_a = true; break;
            }
            if (Parse.Compiler_.Incremented.Contains(v))
                Parse.Err("Variable " + v.Names[v.Names.Count-1] +
                    " incremented/decremented more then once in a statement") ;
            if (v != null)
                Parse.Compiler_.Incremented.Add(v);
            if (E.Type_expr().Kind != Type.Kind_type.INT)
                not_a = true;
            if (E.Is_read_only()) not_a = true;
            if (not_a) Parse.Err("++/-- is not applicable");
        }

        /*
        
        FUNCTION obtain_index_last(
        	{Parser} Parse|_src) ==> {Expr}, NEW
            :
            --------------------------------------- '[ ... * ... ]'
            INT at_pos|ition = Parse.Pos
            Parse.Wait("*")
            {Expr} a|rray_to_get_last = comp(Parse).Current_array
            CASE a == NONE ? 
                 Parse.Err("Operand '*' is not applicable"._Eoper6 )
            ;
            CASE a.Operation == 'FUN' ?
                Parse.Err("Operand '*' can not be used to index "
                "function result"._Eoper7 )
            ;
                
            c|ount_of_items = {Expr}(Operation = 'SYSTEM_FUN',
                Fun_ = comp(Parse).SYSFUN_Count, Items_[] << a),
                OWNED BY comp(Parse).Current_fun
                
            CASE !a.Is_array ? c.Fun_ = comp(Parse).SYSFUN_Len ;
            
            RESULT = {Expr}(Operation = 'BINARY', Sign = 'MINUS', Arg1_ = c,
                At_line = Parse.Line, At_pos = at_pos,
                Type_obj_ = comp(Parse).TYPE_INT, Is_star_operation = TRUE)
                
            RESULT.Arg2_ = {Expr}(Operation = 'CONST', 
                Var_arg = comp(Parse).N1_c), OWNED BY RESULT .
        */
        private static Expression obtain_index_last(Parser Parse)
        {
            int at_pos = Parse.Pos;
            Parse.Wait("*");
            Expression a = Parse.Compiler_.Current_array;
            if (a == null)
            {
                Parse.Err("Operand '*' is not applicable");
                return null;
            }
            if (a.Operation == Operation_kind.FUN)
            {
                Parse.Err("Operand '*' can not be used to index function result");
            }
            Expression c = new Expression();
            c.Operation = Operation_kind.FUN;
            c.Fun_ = Parse.Compiler_.SYSFUN_Count;
            c.Items_.Add(a);
            if (!a.Is_array()) c.Fun_ = Parse.Compiler_.SYSFUN_Len;
            Expression Result = new Expression();
            Result.Operation = Operation_kind.BINARY;
            Result.Sign = Bin.MINUS;
            Result.At_line = Parse.Line;
            Result.At_pos = at_pos;
            Result.Type_obj_ = Parse.Compiler_.TYPE_INT;
            Result.Arg1_ = c;
            Result.Arg2_ = new Expression();
            Result.Arg2_.Operation = Operation_kind.CONST;
            Result.Arg2_.Var_arg = Parse.Compiler_.N1_c;
            return Result;
        }

        /*
        

        FUNCTION Obtain_new|_object({Parser} Parse|_src,
            {Type} T|ype_of_object, BOOL Base|_class) ==> {Expr},
            NEW
            :
            ------------------------------ '{Type} was before, construct object'
            CASE T.Kind !IN ['CLASS', 'STRUCTURE'] ?
                Parse.Err("New object must be of class/structure type"._EnewObj 
                ": " Parse.Next20)
            ;
            CASE T.Modifiers['ABSTRACT'] && !Base && !(
            	comp(Parse).Current_fun.Is_test)
            	?
                Parse.Err("Creating object of abstract class in a function "
                "which is not a TEST"._Ecreat ": " T.Whole_name)
            ;
            {Var} need_init[]
            {Var} done_init[]
            
            RESULT = {Expr}(Operation = 'NEW_OBJ', Type_obj_ = T,
                At_line = Parse.Line, At_pos = Parse.Pos)
                
            CASE T.Construct != NONE ?
            	 comp(Parse).Current_fun.Call_functions_[] << T.Construct ;
                
            T.Has_instances = TRUE
            CASE Parse.Symbol("(") ?
                 INT k|_waiting_brackets = brackets_to_wait(Parse)
                 PUSH comp(Parse).Current_fun.In_new_obj = TRUE :
	             PUSH comp(Parse).In_init = comp(Parse).In_init + 1 :
	                 FOR x|dummy IN [0 TO 1_000_000] :
	                     ------------------------- 'skip block comments'
	                     CASE Parse.Symbol("--") ?
	                         NONE = Parse.Skip_to("'")
	                         Parse.Wait("'")
	                         NONE = Parse.Skip_to("'")
	                         Parse.Wait("'")
	                         CASE Parse.End_of_line ? Parse.Fin ;
	                         CONTINUE x ;
	                     Parse.Skip_sp
	                     CASE Parse.Next_symbol(")") ? BREAK x ;
	                     STR name|_of_field = Parse.Ident
	                     {Var} f|ield_of_obj = T.Find_field(name)
	                     {Type} ftype|_of_field = f.Type_
	                     CASE ftype.Kind == 'ENUM' ?
	                          ftype = ftype.Base_ ;
	                     {Type} cc|urrent_class = comp(Parse).Current_class
	                     CASE ?
	                     [ftype.Kind == 'CLASS' && "{}" !IN ftype.Names[] 
	                      && (
	                      ftype != cc) && (
	                      ftype !IN cc.Import_[]) && (
	                      ftype !IN cc.Debug_import_[]) && !(
	                      comp(Parse).Current_fun.Is_test && (
	                      ftype IN cc.Test_import_[]))] ?
	                          Parse.Err("Field type"._Efield5 
	                          " " f.Whole_name
	                          " " ("is from class"._Eisfrom2 )
	                          " " ftype.Whole_name
	                          " " ("which is not imported"._Ewhich2 ))
	                     [ftype.Kind == 'CLASS' && (
	                     ftype != cc && ftype !IN cc.Used_imports_[])] ?
	                          cc.Used_imports_[] << ftype ;
	                     CASE Base ? T.Init[] << f
	                     ELSE done_init[] << f ;
	                     init_field(Parse, RESULT, f)
	                     CASE !Parse.Symbol(",") ? BREAK x ;
	                 ;
	             ;
                 ;
                 FOR i|dummy IN [1 TO k] : Parse.Wait("]") ;
                 Parse.Wait(")")  ;
            -------------------------- 'check all INIT fields are set'
            //CASE Base || T.Kind == 'OBJECT' ? ==> ;
            CASE Base ? ==> ;
            {Type} me|_or_base_class = T
            FOR i|dummy IN [0 TO MAX_INT-1] :
                CASE me == NONE ? BREAK i ;
                FOR fld IN me.Field[] :
                    CASE fld.Modifiers['INIT'] ? need_init[] << fld ;
                ;
                FOR fld IN me.Init[] : done_init[] << fld ;
                me = me.Base_ ;
			STR not_ini|tialized
            FOR fld IN need_init[] :
                CASE fld !IN done_init[] ?
					 not_ini = not_ini fld.Whole_name ", " ;
            ;
			CASE not_ini == "" ? ==> ;
			not_ini = not_ini.[0 TO *-2]
			PUSH Parse.Pos = RESULT.At_pos :
				CASE "," IN not_ini ?
					 not_ini = "Fields"._Efields " " not_ini
					 STR is_are|_verb = "are"._Eare
				ELSE not_ini = "Field"._Efield3 " " not_ini
					 is_are = "is"._Eis7 ;
					 
				Parse.Err(not_ini " " ("of object of class"._Eof ) 
				" " T.Whole_name
				" " is_are " " ("not initialized:"._Enot2) " " Parse.Next20)
			; .
        */
        static int CNT_Obtain_new_object;

        public static Expression Obtain_new_obj(Parser Parse, Type T, bool Base_class)
        {
            if (CNT_Obtain_new_object++ == 91)
            { }

            if (T != null && T.Kind != Type.Kind_type.CLASS)
                Parse.Err("New object must be of class type: " + Parse.Next20());
            if (T != null && T.Modifiers[(int)Type.Class_mod.ABSTRACT] && !Base_class)
                Parse.Err("Creating object of abstract class: " + T.Name());
            List<Variable> need_init = new List<Variable>();
            List<Variable> done_init = new List<Variable>();
            Expression Result = new Expression();
            Result.Operation = Operation_kind.NEW;
            Result.Type_obj_ = T;
            Result.At_line = Parse.Line;
            Result.At_pos = Parse.Pos;
            if (Parse.Symbol("("))
            {
                Parse.Compiler_.In_init_level++;
                for (int x = Parse.Pos; x <= Parse.Last(); x++)
                {
                    Parse.Skip_sp();
                    string name = Parse.Ident();
                    Variable f = T == null ? null : T.Find_field(name);
                    if (f != null)
                    {
                        if (Base_class)
                            T.Initialized_fields.Add(f);
                        else done_init.Add(f);
                        init_field(Parse, Result, f);
                    }
                    if (!Parse.Symbol(",")) break;
                }
                Parse.Wait(")");
                Parse.Compiler_.In_init_level--;
            }
            //---------------------- 'check all init fields are set'
            if (!Base_class && T != null)
            {
                Type me = T;
                for (int i = 0; i <= int.MaxValue; i++)
                {
                    if (me == null) break;
                    foreach (Variable fld in me.Field)
                        if (fld.Modifiers[(int)Variable.Var_mod.INIT])
                            need_init.Add(fld);
                    foreach (Variable fld in me.Initialized_fields)
                        done_init.Add(fld);
                    me = me.Base_;
                }
                foreach (Variable fld in need_init)
                {
                    if (!done_init.Contains(fld))
                    {
                        int save_pp = Parse.Pos;
                        Parse.Pos = Result.At_pos;
                        Parse.Err("Field " + fld.Names[fld.Names.Count - 1] + " of object of class " +
                        T.Name() + " is not initialized: " + Parse.Next20());
                        Parse.Pos = save_pp;
                    }
                }
            }
            return Result;
        }

        /*
        
        FUNCTION init_field|_of_newly_created_object(
        	{Parser} Parse|_obj,
            {Expr} Obj|ect_new, {Var} F|ield_init)
            :
            ----------------------- 'Field was before, create {Expr} object'
            INT at_pos|ition = Parse.Pos
            
            //DEBUG:
            //      CASE !F.Is_array ? INT dummy_stop = 888 ;
            //; 
            dest|ination = {Expr}(Operation = 'FIELD', Var_arg = F,
                At_line = Parse.Line, At_pos = at_pos //, Arg1_ = Obj
                ), OWNED BY Obj
                
            ---------------------------------------- '[] or [expr]'
            CASE F.Is_array ?
                Parse.Wait("[")
                CASE !Parse.Symbol("]") ?
                    index|operation = {Expr}(Operation = 'INDEX', Arg1_ = dest,
                        At_line = Parse.Line, At_pos = Parse.Pos),
                        OWNED BY Obj
                        
                    index.Arg2_ = Recognize(Parse),
                                >> comp(Parse).Current_fun.All_expr[]
                                
                    dest = index
                    CASE F.Size_type_ != NONE && (
                         index.Arg2_.Type_expr != F.Size_type_)
                         ?
                         PUSH Parse.Pos = at_pos :
                              Parse.Err(
                              "Waiting for index of type"._Ewait6 
                              " " F.Size_type_.Whole_name
                              ": " Parse.Next20)
                    	 ;
                    ;
                    Parse.Wait("]") ;
            ;
            ---------------------------------------- 'Hidden field ?'
            BOOL h|idden_field = !F.Is_public
            
            h &&= ! comp(Parse).Current_class.Is_descend(
                Obj.Type_expr, comp(Parse))
                
            {Type} cc|urrent_class = Parse.Compiler.Current_class
            CASE F.In_type_.Kind == 'STRUCTURE' 
                 && cc.Is_descend(F.In_type_.In_class_, Parse.Compiler)
                 ?
                 h = FALSE ;
                
            CASE h ?
                Parse.Err("Assigning value to the hidden field"._Eassign3 
                " " F.Names[*]) ;
            ---------------------------------------- 'Not writable ?'
            BOOL r|ead_only = !F.Modifiers['INIT'] && (
                 F.Modifiers[{Var}.{var_mod}.'READ'])
                 
            r &&= comp(Parse).Current_class != F.In_type_
            
            r &&= ! comp(Parse).Current_class.Is_descend(
                Obj.Type_expr, comp(Parse))
                
            CASE r ?
                Parse.Err("Assigning value to the read only field"._Eassign4 
                " " F.Names[*]) ;
            ---------------------------------------- 'Assign value'
            {Assign} temp|_assignments[]
            comp(Parse).Current_fun.Compile_assign(dest, temp[])
            FOR t IN temp[] :
                Obj.Assignments_[] << t
                comp(Parse).Current_fun.Keep_statements[] << t ; .
        */
        private static void init_field(Parser Parse, Expression Obj, Variable F)
        {
            int at_pos = Parse.Pos;
            Expression dest = new Expression();
            dest.Operation = Operation_kind.FIELD;
            dest.Var_arg = F;
            dest.At_line = Parse.Line;
            dest.At_pos = Parse.Pos;
            if (F.Is_array)
            {
                Parse.Wait("[");
                if (!Parse.Symbol("]"))
                {
                    Expression index = new Expression();
                    index.Operation = Operation_kind.INDEX;
                    index.Arg1_ = dest;
                    index.At_line = Parse.Line;
                    index.At_pos = Parse.Pos;
                    index.Arg2_ = Expression.Recognize(Parse);
                    dest = index;
                    if (F.Size_type_ != null && index.Arg2_ != null && 
                        F.Size_type_ != index.Arg2_.Type_expr())
                    {
                        int save = Parse.Pos;
                        Parse.Pos = at_pos;
                        Parse.Err("Waiting for index of type " + F.Size_type_.Name() +
                            ": " + Parse.Next20());
                        Parse.Pos = save;
                    }
                    Parse.Wait("]");
                }
            }
            //------------------------------------ 'hidden ?'
            bool hidden = !F.Is_public() && 
                 !Parse.Compiler_.Current_class.Is_descendant_of(Obj.Type_expr(), Parse.Compiler_);
            if (hidden)
                Parse.Err("Assigning hidden field " + F.Names[F.Names.Count - 1]);
            //------------------------------------ 'read only ?'
            bool read = !F.Modifiers[(int)Variable.Var_mod.INIT] &&
                F.Modifiers[(int)Variable.Var_mod.READ];
            if (read)
                Parse.Err("Assigning read only field " + F.Names[F.Names.Count - 1]);
            //------------------------------------ 'assign value'
            Parse.Compiler_.Current_fun.Compile_assign(dest, Obj.Assignments_, at_pos);
        }

        /*
        
        FUNCTION obtain_array({Parser} Parse|_src) ==> {Expr}, NEW :
            ----------------------------------- '[value, value, ... ]'
            RESULT = {Expr}(Operation = 'ARRAY', At_line = Parse.Line,
                At_pos = Parse.Pos)
                
            Parse.Wait("[")
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                {Expr} it|em_of_array = Recognize(Parse),
                               >> comp(Parse).Current_fun.All_expr[]
                               
                RESULT.Items_[] << it
                CASE it.Operation != 'CONST' ?
                    Parse.Err("Array construction must contain only "
                    "constant items"._Earray )
                ;
                check_compat_items(RESULT, Parse)
                CASE !Parse.Symbol(",") ? BREAK x ;
            ;
            Parse.Wait("]") .
        */
        private static Expression obtain_array(Parser Parse)
        {
            Expression Result = new Expression();
            Result.At_line = Parse.Line;
            Result.At_pos = Parse.Pos;
            Parse.Wait("[");
            Result.Operation = Operation_kind.ARRAY;
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                Expression it = Expression.Recognize(Parse);
                Result.Items_.Add(it);
                if (it.Operation != Operation_kind.CONST)
                    Parse.Err("Array construction must contain only " +
                    "constant items");
                check_compat_items(Result, Parse);
                if (!Parse.Symbol(",")) break;
            }
            Parse.Wait("]");
            return Result;
        }

        /*
        
        FUNCTION check_compat_items|_array_constructor(
        {Expr} A|rray_expr, {Parser} Parse|_src)
            :
            --------------------------------- 'Values in [...] are compatible ?'
            FOR it IN A.Items_[] :
                CASE it.Index == 0 ?
                    A.Type_obj_ = it.Type_expr
                    CONTINUE it ;
                CASE A.Items_[0].Type_expr.Kind ?
                    ['BOOL', 'ENUM', 'STR']:
                        BOOL ok|_compatible
                        ok = it.Type_expr == A.Items_[0].Type_expr
                    ['INT', 'REAL']:
                        ok = it.Type_expr.Kind IN ['INT', 'REAL']
                        A.Type_obj_ = int_or_real(A.Type_obj_, it.Type_expr)
                    ['CLASS']:
                        ok = it.Type_expr.Is_descend(A.Type_obj_, comp(Parse))
                        	 || A.Type_obj_ == it.Type_expr
                    ['STRUCTURE']:
                		ok = it.Type_expr == A.Items_[0].Type_expr
                ;
                CASE !ok ?
                     PUSH Parse.Pos = it.At_pos :
                          Parse.Err("Item #"._Eitem it.Index.Str 
                          " " ("is not compatible with all previous items of "
                          "the array"._Eisnot5 ) ": " Parse.Next20) ;
                ;
            ; .
        */
        private static void check_compat_items(Expression A, Parser Parse)
        {
            int INDEX = -1;
            foreach (Expression it in A.Items_)
            {
                INDEX++;
                if (INDEX == 0)
                {
                    A.Type_obj_ = it == null ? null : it.Type_expr();
                    continue;
                }
                bool ok = false;
                switch (A.Items_[0].Type_expr().Kind)
                {
                    case Type.Kind_type.BOOL:
                    case Type.Kind_type.ENUM:
                    case Type.Kind_type.STR:
                        ok = it.Type_expr() == A.Items_[0].Type_expr();
                        A.Type_obj_ = it.Type_expr();
                        break;
                    case Type.Kind_type.INT:
                    case Type.Kind_type.REAL:
                        ok = it.Type_expr().Kind == Type.Kind_type.INT ||
                            it.Type_expr().Kind == Type.Kind_type.REAL;
                        if (it.Type_expr().Kind == Type.Kind_type.REAL)
                            A.Type_obj_ = it.Type_expr();
                        break;
                    case Type.Kind_type.CLASS:
                        if (!it.Type_expr().Is_descendant_of(A.Type_obj_, Parse.Compiler_))
                        {
                            int save_pos = Parse.Pos;
                            Parse.Pos = it.At_pos;
                            Parse.Err("Item #" + INDEX.ToString() + " is not " +
                                "compatible with all previos items of the array: " + 
                                Parse.Next20());
                            Parse.Pos = save_pos;
                        }
                        else A.Type_obj_ = it.Type_expr();
                        break;
                    default: Parse.Err("Internal error - type kind " +
                        Type.Kind_type_names[(int)A.Items_[0].Type_expr().Kind] +
                        " was not handled");
                        break;
                }
            }

        }

        /*
        FUNCTION int_or_real({Type} T1|_int_real,
            {Type} T2|_int_real) ==> {Type}
            :
            ------------------------------------ 'Most power type of two'
            CASE T2.Kind == 'REAL' ?
                 RESULT = T2
            ELSE RESULT = T1 ; .
        */
        private static Type int_or_real(Type T1, Type T2)
        {
            if (T2.Kind == Type.Kind_type.REAL) return T2;
            return T1;
        }

        /*
        
        METHOD Copy_location({Expression}E|xpr_from) :
            At_line = E.At_line
            At_pos = E.At_pos .
        */
        public void Copy_location(Expression E)
        {
            At_line = E.At_line;
            At_pos = E.At_pos;
        }

        /*
        
        METHOD Is_weak|_reference ==> BOOL, RECURSIVE :
            CASE Operation ?
                ['VAR', 'FIELD']: RESULT = Var_arg.Names[0].[*] == "_"
                
                ['INDEX']: RESULT = Arg1_.Is_weak
                
                ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ', 'ARRAY',
                 'AS', 'CONST', 'UNKNOWN', 'INT2REAL', 'NOT_B',
                 'NOT', 'NEG']: RESULT = FALSE
            ; .
        */
        public bool Is_weak()
        {
            switch (Operation)
            {
                case Operation_kind.VAR:
                case Operation_kind.FIELD:
                    return StringFunctions.Ending(Var_arg.Names[0], "_");
                case Operation_kind.INDEX:
                    return Arg1_.Is_weak();
                default: return false;
            }
        }

        /*
        
		FUNCTION New_str|ing_constant(
            {Parser} Parse|_to_refer_to_compiler,
            STR Value|_constant) ==> {Expr}, NEW
            :
			------------------------------------------------------ ''
			RESULT = {Expr}(Operation = 'CONST', Var_arg = {Var}(
				Line = -3, Type_ = comp(Parse).TYPE_STR, Is_const= TRUE,
				Str_c = Value)),
				OWNED BY comp(Parse).Current_fun .
		
		
        METHOD Test_output|_expression(
        	STR Level|_indent), RECURSIVE
        	:
			<< Level "EXPRESSION Total_obj_index=" Total_obj_index(THIS).Str
			   " Kind=" Operation.Name
			   
			CASE Is_array ? << " Is_array"
				 CASE Is_fixed ? << " Is_fixed" ;
			;
			CASE Operation ?
			['UNKNOWN']: << #NL
			['BINARY']: 
			    << " op=" Sign.Name #NL
				CASE Arg1_ != NONE ?
	            	 << Level "Arg1_="
	            	 Arg1_.Test_output(Level "  ")
	            	 << Level "Arg2_="
	            	 Arg2_.Test_output(Level "  ") ==> ;
				FOR it IN Items_[] :
				    << Level "item[" it.Index.Str "]="
				    it.Test_output(Level "  ") ;
			['FUN', 'BASE_FUN', 'SYSTEM_FUN']: << " fun=" Fun_.Names[0] #NL
				FOR it IN Items_[] :
				    << Level "param[" it.Index.Str "]="
				    it.Test_output(Level "  ") ;
            ['VAR']: << " var=" Var_arg.Names[0] #NL
            ['INDEX']: << #NL
            	<< Level "Arg1_="
            	Arg1_.Test_output(Level "  ")
            	<< Level "Arg2_="
            	Arg2_.Test_output(Level "  ")
            	CASE Arg3_ != NONE ?
            		 << Level "Arg3_="
            		 Arg3_.Test_output(Level "  ") ;
            ['FIELD']: << " field=" Var_arg.Names[0] #NL 
            	<< Level "Arg1_="
            	Arg1_.Test_output(Level "  ")
            ['NEW_OBJ']: << #NL
            ['ARRAY']:
				FOR it IN Items_[] :
					<< Level "item[" it.Index.Str "]="
				    it.Test_output(Level "  ") ;
            ['AS']: << #NL
            ['CONST']:
            	CASE Var_arg.Type_.Kind ?
            	['BOOL']: 
				    CASE Var_arg.Int_c != 0 ? << "TRUE" #NL
				    ELSE << "ELSE" #NL ;
            	['INT', 'ENUM']: << Var_arg.Int_c.Str #NL
            	['REAL']: << Var_arg.Real_c.Str #NL
            	['STR']: << Var_arg.Str_c #NL
            	['CLASS', 'STRUCTURE']: NONE ;
            ['INT2REAL']:
				    << "(REAL)("#NL
				    Arg1_.Test_output(Level "  ")
				    << ")"#NL
            ['NOT_B']:	<< "(~" 
            			Arg1_.Test_output(Level "  ") 
            			<< ")"#NL
            ['NOT']: << "(!" 
            		 Arg1_.Test_output(Level "  ") 
            		 << ")"#NL
            ['NEG']: << "(-" 
            		 Arg1_.Test_output(Level "  ") 
            		 << ")"#NL
            ; .
			
        DESTRUCT :
            ---------------------------------------- '{Expr} destruct'
            // this destructor is especially to debug some key feature of 
            // the AL-IV 
            .
            
        */
    }
}
/*

END

*/

