//Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов. public function_node select_function(expressions_list parameters, SymbolInfo functions, location loc, List<SyntaxTree.expression> syntax_nodes_parameters = null) { if (functions==null) { AddError(new NoFunctionWithThisName(loc)); } function_node_list set_of_possible_functions = new function_node_list(); bool is_alone_method_defined = (functions.Next == null); function_node first_function = functions.sym_info as function_node; bool _is_assigment = first_function.name == compiler_string_consts.assign_name; basic_function_node _tmp_bfn = functions.sym_info as basic_function_node; List<function_node> indefinits = new List<function_node>(); while(functions!=null) { #if (DEBUG) if (functions.sym_info.general_node_type!=general_node_type.function_node && functions.sym_info.general_node_type != general_node_type.property_node) { throw new CompilerInternalError("Function name is used to define another kind of object."); } #endif function_node fn = null; if (functions.sym_info.general_node_type == general_node_type.property_node) { fn = (functions.sym_info as property_node).get_function; } else fn=(function_node)functions.sym_info; if (fn.node_kind == node_kind.indefinite) { indefinits.Add(fn); } else if (fn.node_kind==SemanticTree.node_kind.common) { common_function_node cfn=(common_function_node)fn; if ((parameters.Count>=cfn.parameters.Count-cfn.num_of_default_variables)&& (parameters.Count<=cfn.parameters.Count) || parameters.Count == 0 && cfn.parameters.Count == 1 && cfn.parameters[0].is_params) { if (is_exist_eq_method_in_list(fn,set_of_possible_functions) != null) { //!!!!!!!!!!!!! //DS TODO //Это нужно чтобы была возможность создавать операторы = := ..., т.к. всегда они добавляюся автоматом //Надо сначало просматривать заголовки и добавлять такие операторы только если нужно. if (set_of_possible_functions.Count > 0) if (set_of_possible_functions[0] is basic_function_node) { set_of_possible_functions.remove(set_of_possible_functions[0]); set_of_possible_functions.AddElement(fn); } //!!!!!!!!!!!!! functions=functions.Next; continue; } set_of_possible_functions.AddElement(fn); } } else { //TODO: Здесь нужно поправить, если создавать возможность вызова метода с параметрами по умолчанию из откомпилированной dll. if (parameters.Count==fn.parameters.Count) { function_node func = null; if ((func=is_exist_eq_method_in_list(fn,set_of_possible_functions)) != null) { if (!eq_type_nodes(fn.return_value_type, func.return_value_type)) { set_of_possible_functions[set_of_possible_functions.IndexOf(func)] = fn; } functions = functions.Next; continue; } set_of_possible_functions.AddElement(fn); } } if (parameters.Count > fn.parameters.Count) { if (fn.parameters.Count > 0) { if ((fn.parameters[fn.parameters.Count - 1]).is_params) { //+DS ms0105 if (is_exist_eq_method_in_list(fn, set_of_possible_functions) != null) { functions = functions.Next; continue; } //-DS set_of_possible_functions.AddElement(fn); } } } else if ((parameters.Count == 0 && fn.parameters.Count == 1) && fn.parameters[0].is_params && !set_of_possible_functions.Contains(fn)) set_of_possible_functions.AddElement(fn); else if (fn.num_of_default_parameters != 0 && parameters.Count >= fn.parameters.Count - fn.num_of_default_parameters) { if (!set_of_possible_functions.Contains(fn)) set_of_possible_functions.AddElement(fn); } else if (parameters.Count == 1 && fn is common_namespace_function_node && (fn as common_namespace_function_node).ConnectedToType != null && fn.parameters.Count == 2 && fn.parameters[1].is_params) set_of_possible_functions.AddElement(fn); functions=functions.Next; } if (set_of_possible_functions.Count==0 && indefinits.Count == 0) { AddError(new NoFunctionWithSameParametresNum(loc, is_alone_method_defined, first_function)); } //(ssyy) Инициализируем is_alone_defined FailedWhileTryingToCompileLambdaBodyWithGivenParametersException lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = null; if (set_of_possible_functions.Count == 1 && indefinits.Count == 0) { is_alone_method_defined = true; } //(ssyy) Инстанцируем дженерики for (int i = set_of_possible_functions.Count - 1; i > -1; --i) { function_node func = set_of_possible_functions[i]; if (func.is_generic_function) { try { function_node inst = generic_convertions.DeduceFunction(func, parameters, is_alone_method_defined, loc, syntax_nodes_parameters); if (inst == null) { set_of_possible_functions.remove_at(i); } else { set_of_possible_functions[i] = inst; } } catch (FailedWhileTryingToCompileLambdaBodyWithGivenParametersException exc) //lroman Отлавливаем последнее исключение, которое возникло при попытке скомпилировать тело лямбды с заданными типами параметров { set_of_possible_functions.remove_at(i); lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = exc; } } } if (lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException != null && set_of_possible_functions.Count == 0 && indefinits.Count == 0) { throw lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException.ExceptionOnCompileBody; // Если перебрали все, но ничто не подошло, то кидаем последнее исключение } if (set_of_possible_functions.Count == 0 && indefinits.Count == 0) { AddError(loc, "CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS", first_function.name); } possible_type_convertions_list_list tcll = new possible_type_convertions_list_list(); for(int i=0;i<set_of_possible_functions.Count;i++) { possible_type_convertions_list tc=get_conversions(parameters,set_of_possible_functions[i].parameters, is_alone_method_defined,loc); tcll.AddElement(tc); } int j=0; while(j<set_of_possible_functions.Count) { if (tcll[j]==null && set_of_possible_functions[j].node_kind != node_kind.indefinite) { tcll.remove_at(j); set_of_possible_functions.remove_at(j); } else { j++; } } if (set_of_possible_functions.Count==0 && indefinits.Count == 0) { if (_is_assigment && parameters.Count == 2) AddError(new CanNotConvertTypes(parameters[1], parameters[1].type, parameters[0].type, parameters[1].location)); if (_tmp_bfn != null && parameters.Count == 2) AddError(new OperatorCanNotBeAppliedToThisTypes(_tmp_bfn.name, parameters[0], parameters[1],loc)); AddError(new NoFunctionWithSameArguments(loc,is_alone_method_defined)); } bool remove=true; while(remove) { if (set_of_possible_functions.Count==1) { check_single_possible_convertion(loc,tcll[0]); convert_function_call_expressions(set_of_possible_functions[0],parameters,tcll[0]); return set_of_possible_functions[0]; } remove=false; var i = 0; while (i < set_of_possible_functions.Count-1) { j = i+1; while (j < set_of_possible_functions.Count) { method_compare mc = compare_methods(set_of_possible_functions[i], set_of_possible_functions[j], tcll[i], tcll[j]); if (mc == method_compare.greater_method) { tcll.remove_at(j); set_of_possible_functions.remove_at(j); remove = true; } else if (mc == method_compare.less_method) { tcll[i] = tcll[j]; set_of_possible_functions[i] = set_of_possible_functions[j]; tcll.remove_at(j); set_of_possible_functions.remove_at(j); remove = true; } else { j++; } } i++; } } // TODO: Исправить этот алгоритм, сделав каждый с каждым - вроде исправил - см. выше /*j = 1; while(j<set_of_possible_functions.Count) { method_compare mc = compare_methods(set_of_possible_functions[0], set_of_possible_functions[j], tcll[0], tcll[j]); if (mc==method_compare.greater_method) { tcll.remove_at(j); set_of_possible_functions.remove_at(j); remove=true; } else if (mc==method_compare.less_method) { tcll[0]=tcll[j]; set_of_possible_functions[0]=set_of_possible_functions[j]; tcll.remove_at(j); set_of_possible_functions.remove_at(j); remove=true; } else { j++; } } }*/ /*remove=true; while (remove) { if (set_of_possible_functions.Count == 1) { check_single_possible_convertion(loc, tcll[0]); convert_function_call_expressions(set_of_possible_functions[0], parameters, tcll[0]); return set_of_possible_functions[0]; } remove = false; j = 1; while (j < set_of_possible_functions.Count) { } }*/ //Тут некоторое дублирование кода, но сюда программа не должна никогда зайти. //Должен быть выполнен if выше. //Но пусть пока повисит. Потом нужно разобраться и убрать. /*if (set_of_possible_functions.Count==1) { check_single_possible_conversion(func_call,tcll[0]); func_call.function=set_of_possible_functions[0]; convert_function_call_expressions(func_call,tcll[0]); func_call.type=func_call.function.return_value_type; return func_call; }*/ //Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений //в дальнейшем может вызвать странное поведение, это надо проверить if (set_of_possible_functions.Count == 2 && indefinits.Count == 0) if (set_of_possible_functions[0] is basic_function_node && set_of_possible_functions[1] is basic_function_node) return set_of_possible_functions[0]; if (indefinits.Count > 0) { if (indefinits.Count == 1 && set_of_possible_functions.Count == 0) { return indefinits[0]; } indefinits.AddRange(set_of_possible_functions); return new indefinite_functions_set(indefinits); } bool exist_indefinite_parameter = false; foreach (expression_node par in parameters) { if (par.type.depended_from_indefinite) { exist_indefinite_parameter = true; break; } } if (exist_indefinite_parameter) { indefinits.AddRange(set_of_possible_functions); return new indefinite_functions_set(indefinits); } AddError(new SeveralFunctionsCanBeCalled(loc,set_of_possible_functions)); return null; }