// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) //Некоторые алгоритмы . В основном выбор перегруженного метода. Сильно связан с syntax_tree_visitor. using System; using System.Collections.Generic; using System.Linq; using PascalABCCompiler.SemanticTree; using PascalABCCompiler.TreeRealization; namespace PascalABCCompiler.TreeConverter { public class convertion_data_and_alghoritms { internal SymbolTable.TreeConverterSymbolTable symtab=SymbolTable.SymbolTableController.CurrentSymbolTable; private PascalABCCompiler.Errors.SyntaxError _parser_error; private syntax_tree_visitor _stv; private type_constructor _type_constructor; public statement_list_stack statement_list_stack = new statement_list_stack(); //private special_operation_kind _current_operation_kind= special_operation_kind.none; public convertion_data_and_alghoritms(syntax_tree_visitor stv) { type_table.type_table_function_call_maker = create_simple_function_call; _stv=stv; _type_constructor = new type_constructor(this); SystemLibrary.SystemLibrary.type_constructor = _type_constructor; } private void AddError(Errors.Error err) { syntax_tree_visitor.AddError(err); } private T AddError(Errors.Error err) { syntax_tree_visitor.AddError(err, true); return default(T); } private T AddError(location loc, string ErrString, params string[] values) { syntax_tree_visitor.AddError(loc, ErrString, values); return default(T); } private void AddError(location loc, string ErrString, params string[] values) { syntax_tree_visitor.AddError(loc, ErrString, values); } public void reset() { symtab.Clear(); _type_constructor.reset(); statement_list_stack.clear(); arr_nums = 0; //_current_operation_kind = special_operation_kind.none; } /* public special_operation_kind current_operation_kind { get { return _current_operation_kind; } set { _current_operation_kind = value; } } */ internal void statement_list_stack_push(statements_list sl) { sl.Scope = new SymbolTable.BlockScope(symbol_table, syntax_tree_visitor.context.CurrentScope); statement_list_stack.push(sl); } internal SymbolTable.Scope create_block_scope() { return new SymbolTable.BlockScope(symbol_table, syntax_tree_visitor.context.CurrentScope); } internal void statement_list_stack_push(statements_list sl, SymbolTable.Scope Scope) { sl.Scope = Scope; statement_list_stack.push(sl); } internal statements_list statement_list_stack_pop() { return statement_list_stack.pop(); } internal statements_list statement_list_stack_first() { return statement_list_stack.first(); } public type_constructor type_constructor { get { return _type_constructor; } } public PascalABCCompiler.Errors.SyntaxError parser_error { get { return _parser_error; } set { _parser_error = value; } } public System.Collections.Hashtable bad_nodes_in_syntax_tree; public SymbolTable.TreeConverterSymbolTable symbol_table { get { return symtab; } } //TODO: Наверно это свойство вообще не нужно. public syntax_tree_visitor syntax_tree_visitor { get { return _stv; } } //TODO: Избавиться от дублирования метода. public location get_location(semantic_node sn) { SemanticTree.ILocated iloc=sn as SemanticTree.ILocated; if (iloc==null) { return null; } document doc = _stv.CurrentDocument; location loc=null; //DarkStar changed //В PCU не сохраняются location некоторых конструкций, например //числовых констант итд. Поэтому необохдимо делать эту проверку. //Коля может всетаки нужно хранить? if (iloc.Location != null) loc = new location(iloc.Location.begin_line_num, iloc.Location.begin_column_num, iloc.Location.end_line_num, iloc.Location.end_column_num, doc); return loc; } //TODO: Избавиться от этого метода. Везде должен быть только location (а не ILocation). private location loc_to_loc(SemanticTree.ILocation l) { if (l == null) { return null; } document d = new document(l.document.file_name); if (d == null) d = syntax_tree_visitor.CurrentDocument; location loc = new location(l.begin_line_num, l.begin_column_num, l.end_line_num, l.end_column_num, d); return loc; } //TODO: Вообще нужен-ли этот набор методов (create_..._function_call)? private basic_function_call create_basic_function_call(basic_function_node bfn,SemanticTree.ILocation loc,params expression_node[] exprs) { basic_function_call bfc=new basic_function_call(bfn,loc_to_loc(loc)); bfc.parameters.AddRange(exprs); return bfc; } private common_namespace_function_call create_common_namespace_function_call(common_namespace_function_node cnfn, SemanticTree.ILocation loc,params expression_node[] exprs) { common_namespace_function_call cnc=new common_namespace_function_call(cnfn,loc_to_loc(loc)); cnc.parameters.AddRange(exprs); return cnc; } private common_static_method_call create_common_static_method_call(common_method_node cmn,SemanticTree.ILocation loc, params expression_node[] exprs) { #if (DEBUG) if (cmn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Not static method can not be called as static"); } #endif common_static_method_call csmc=new common_static_method_call(cmn,loc_to_loc(loc)); csmc.parameters.AddRange(exprs); return csmc; } public variable_reference CreateVariableReference(var_definition_node vd, location loc) { switch (vd.semantic_node_type) { case semantic_node_type.local_variable: return new local_variable_reference((local_variable)vd, 0, loc); case semantic_node_type.class_field: if (vd.polymorphic_state == polymorphic_state.ps_static) return new static_class_field_reference((class_field)vd, loc); else return new class_field_reference((class_field)vd, syntax_tree_visitor.GetCurrentObjectReference((vd as class_field).cont_type.Scope,vd,loc), loc); case semantic_node_type.namespace_variable: return new namespace_variable_reference((namespace_variable)vd, loc); case semantic_node_type.local_block_variable: return new local_block_variable_reference((local_block_variable)vd, loc); } throw new NotSupportedError(loc); } private common_in_function_function_call create_common_in_function_function_call(common_in_function_function_node cfn, int static_depth,location loc,params expression_node[] exprs) { common_in_function_function_call cc=new common_in_function_function_call(cfn,static_depth,loc); cc.parameters.AddRange(exprs); return cc; } private common_method_call create_common_method_call(common_method_node cmn,location loc,expression_node obj, params expression_node[] exprs) { #if (DEBUG) if (cmn.polymorphic_state==SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Static method can not be called with type"); } #endif common_method_call cmc=new common_method_call(cmn,obj,loc); cmc.virtual_call = !syntax_tree_visitor.inherited_ident_processing; cmc.parameters.AddRange(exprs); return cmc; } private compiled_function_call create_compiled_function_call(compiled_function_node cfn, location loc, expression_node obj,params expression_node[] exprs) { #if (DEBUG) if (cfn.polymorphic_state==SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Static method can not be called with type"); } #endif compiled_function_call cfc=new compiled_function_call(cfn,obj,loc); cfc.virtual_call = !syntax_tree_visitor.inherited_ident_processing; cfc.parameters.AddRange(exprs); return cfc; } private compiled_static_method_call create_compiled_static_method_call(compiled_function_node cfn, location loc, params expression_node[] exprs) { #if (DEBUG) if (cfn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Not static method can not be called as static"); } #endif compiled_static_method_call csmc=new compiled_static_method_call(cfn,loc); csmc.parameters.AddRange(exprs); return csmc; } public expression_node create_compiled_construcor_call(compiled_constructor_node fn, location loc, params expression_node[] exprs) { compiled_constructor_call ccc = new compiled_constructor_call(fn, loc); ccc.parameters.AddRange(exprs); return ccc; } //Метод только для внутнреннего использования. //НЕ ПРЕОБРАЗУЕТ ТИПЫ. Только создает узел вызова метода. //Этот метод и используется для создания узлов преобразования типов. //TODO: Переименовать. public expression_node create_simple_function_call(function_node fn, location loc, params expression_node[] exprs) { if (fn.compile_time_executor != null) { expression_node ex = fn.compile_time_executor(loc, exprs); if (ex != null) { return ex; } } switch (fn.semantic_node_type) { case semantic_node_type.basic_function_node: { return create_basic_function_call((basic_function_node)fn, loc, exprs); } case semantic_node_type.common_namespace_function_node: { return create_common_namespace_function_call((common_namespace_function_node)fn, loc, exprs); } case semantic_node_type.common_method_node: { common_method_node cmn = (common_method_node)fn; if (cmn.polymorphic_state != SemanticTree.polymorphic_state.ps_static) { break; } return create_common_static_method_call(cmn, loc, exprs); } /* case semantic_node_type.pseudo_function: { pseudo_function pf=(pseudo_function)fn; return pf.execute_pseudo_function_algorithm(loc,exprs); } */ case semantic_node_type.common_in_function_function_node: break; case semantic_node_type.compiled_function_node: { compiled_function_node cfn = (compiled_function_node)fn; if (cfn.polymorphic_state != SemanticTree.polymorphic_state.ps_static) { break; } return create_compiled_static_method_call(cfn, loc, exprs); } case semantic_node_type.compiled_constructor_node: { compiled_constructor_call ccc = new compiled_constructor_call((compiled_constructor_node)fn,loc); ccc.parameters.AddRange(exprs); return ccc; } case semantic_node_type.indefinite_definition_node: { indefinite_function_call ifc = new indefinite_function_call(fn, loc); ifc.parameters.AddRange(exprs); return ifc; } default: throw new CompilerInternalError("Unknown function type"); } throw new CanNotReferenceToNonStaticMethodWithType(fn.name, loc); } public expression_node create_method_call(function_node fn, location loc, expression_node obj, params expression_node[] exprs) { if (fn.compile_time_executor != null) { expression_node ex = fn.compile_time_executor(loc, exprs); if (ex != null) { return ex; } } switch (fn.semantic_node_type) { case semantic_node_type.common_method_node: { common_method_node cmn = (common_method_node)fn; return create_common_method_call(cmn, loc, obj, exprs); } case semantic_node_type.compiled_function_node: { compiled_function_node cfn = (compiled_function_node)fn; return create_compiled_function_call(cfn, loc, obj, exprs); } default: throw new CompilerInternalError("Unknown function type"); } } /// /// Этот метод вызывается если мы встречаем простой вызов функии, например f(1). /// Он определяет является ли эта функция методом класса, вложенной функцией и т.д. и создает соответствующее обращение. /// Например, для метода класса он добавляет this, а для вложенной функции вычисляет статическую глубину. /// /// Список параметров. /// Список методов. /// Расположение вызова. /// Тип в котором мы находимся. null, если мы вне типа. /// Функция в которой мы находимся. /// Может ли это быть вызов процедуры. false если вызов стоит в выражении или правой части опреатора присваивания. /// Возвращает узел вызова метода. public expression_node create_full_function_call(expressions_list exprs, List si, location loc, common_type_node converted_type, common_function_node top_function, bool allow_procedure) { function_node fn = select_function(exprs, si, loc); //allow_procedure = true; if ((!allow_procedure) && (fn.return_value_type == null)) { throw new SimpleSemanticError(loc, "FUNCTION_EXPECTED_PROCEDURE_{0}_MEET", fn.name); } if (fn.return_value_type is undefined_type) throw new SimpleSemanticError(loc, "RETURN_TYPE_UNDEFINED_{0}", fn.name); expression_node expr_node = null; switch (fn.semantic_node_type) { case semantic_node_type.basic_function_node: case semantic_node_type.common_namespace_function_node: { expr_node = create_simple_function_call(fn, loc, exprs.ToArray()); break; } case semantic_node_type.common_method_node: case semantic_node_type.compiled_function_node: { SemanticTree.IClassMemberNode icmn = (SemanticTree.IClassMemberNode)fn; if (icmn.polymorphic_state == SemanticTree.polymorphic_state.ps_static) { expr_node = create_simple_function_call(fn, loc, exprs.ToArray()); break; } //expression_node tn = new this_node(converted_type,loc); base_function_call cmc = null; switch (fn.semantic_node_type) { case semantic_node_type.common_method_node: { //ssyy добавил if (((common_method_node)fn).is_constructor) { common_constructor_call ccc = new common_constructor_call((common_method_node)fn, loc); //(ssyy) По-видимому, здесь всегда можно присваивать false, так как при создании нового объекта мы сюда не заходим... ccc._new_obj_awaited = false; if (!syntax_tree_visitor.context.allow_inherited_ctor_call && !syntax_tree_visitor.context.can_call_inherited_ctor_call(statement_list_stack_first())) { if (syntax_tree_visitor.inherited_ident_processing) syntax_tree_visitor.AddError(new SimpleSemanticError(loc, "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST")); else syntax_tree_visitor.AddError(new SimpleSemanticError(loc, "CAN_NOT_CALL_CONSTRUCTOR_AS_PROCEDURE")); } cmc = ccc; } else //\ssyy { if (fn is generic_method_instance_node) { common_method_node cmn = (fn as generic_method_instance_node).original_function as common_method_node; cmc = new common_method_call((common_method_node)fn, syntax_tree_visitor.GetCurrentObjectReference(cmn.cont_type.Scope, fn, loc), loc); } else cmc = new common_method_call((common_method_node)fn, syntax_tree_visitor.GetCurrentObjectReference(((common_method_node)fn).cont_type.Scope, fn, loc), loc); (cmc as common_method_call).virtual_call = !syntax_tree_visitor.inherited_ident_processing; } break; } case semantic_node_type.compiled_function_node: { cmc = new compiled_function_call((compiled_function_node)fn, syntax_tree_visitor.GetCurrentObjectReference(((compiled_function_node)fn).cont_type.Scope, fn, loc), loc); (cmc as compiled_function_call).virtual_call = !syntax_tree_visitor.inherited_ident_processing; break; } } cmc.parameters.AddRange(exprs); expr_node = cmc; break; } case semantic_node_type.common_in_function_function_node: { common_in_function_function_node cffn = (common_in_function_function_node)fn; common_in_function_function_call cffc = new common_in_function_function_call(cffn, symtab.GetRelativeScopeDepth(cffn.function.scope, top_function.scope), loc); cffc.parameters.AddRange(exprs); expr_node = cffc; break; } //ssyy добавил case semantic_node_type.compiled_constructor_node: { compiled_constructor_node ccn = fn as compiled_constructor_node; if (ccn == null) { throw new CompilerInternalError("compiled_constructor_node expected"); } compiled_constructor_call ccc = new compiled_constructor_call(ccn, loc); ccc.parameters.AddRange(exprs); ccc._new_obj_awaited = false; if (!syntax_tree_visitor.context.allow_inherited_ctor_call && !syntax_tree_visitor.context.can_call_inherited_ctor_call(statement_list_stack_first())) { throw new SimpleSemanticError(loc, "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST"); } expr_node = ccc; break; } case semantic_node_type.indefinite_definition_node: { indefinite_function_call ifc = new indefinite_function_call(fn, loc); ifc.parameters.AddRange(exprs); expr_node = ifc; break; } //\ssyy default: { throw new NotSupportedError(loc); } } return expr_node; } /// /// Проверяет, что оператор статический метод класса. /// /// Функция-оператор. public void check_operator(function_node fn) { switch (fn.semantic_node_type) { case semantic_node_type.common_in_function_function_node: { throw new CompilerInternalError("Operator can not be nested in function function."); } case semantic_node_type.common_method_node: { common_method_node cmn=(common_method_node)fn; if (cmn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Operator can not be non static method"); } break; } case semantic_node_type.compiled_function_node: { compiled_function_node cfn=(compiled_function_node)fn; if (cfn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static) { throw new CompilerInternalError("Operator can not be non static method. Included library is can be corrupted or library data extraction error."); } break; } } } /// /// Создает узел преобразования типа, если необходимо. /// /// Выражение исходного типа. /// К какому типу нужно преобразовать. /// Преобразованное выражение. public expression_node convert_type(expression_node en, type_node to) { return convert_type(en, to, en.location); } /// /// Проверяет можно ли неявно преобразовать. Если надо кидает исключение /// /// Выражение исходного типа. /// К какому типу нужно преобразовать. public void check_convert_type(expression_node en, type_node to, location loc) { if (en.type == to) return; possible_type_convertions pct = type_table.get_convertions(en.type, to); if (pct.second != null) throw new TwoTypeConversionsPossible(en, pct.first, pct.second); if (pct.first == null) throw new CanNotConvertTypes(en, en.type, to, loc); } public bool can_convert_type(expression_node en, type_node to) { if (en.type == to) return true; possible_type_convertions pct = type_table.get_convertions(en.type, to); if (pct.second != null) return false; if (pct.first == null) return false; return true; } public void check_convert_type_with_inheritance(type_node from, type_node to, location loc) { if (from == to) return; possible_type_convertions pct = type_table.get_convertions(from, to); if (pct.second != null) throw new TwoTypeConversionsPossibleT(pct.first, pct.second, loc); if (pct.first == null /*&& !type_table.is_derived(from, to)*/) throw new CanNotConvertTypes(null, from, to, loc); } /// /// Создает узел преобразования типа, если необходимо. /// /// Выражение исходного типа. /// К какому типу нужно преобразовать. /// Явный контекст. /// Преобразованное выражение. public expression_node convert_type(expression_node en,type_node to, location loc) { if (en.type==to) { return en; } //TODO: А если наследование? possible_type_convertions pct=type_table.get_convertions(en.type,to); if (pct.second!=null) { AddError(new TwoTypeConversionsPossible(en,pct.first,pct.second)); } if (pct.first==null) { if (to is delegated_methods && (to as delegated_methods).empty_param_method != null) { return convert_type(en, (to as delegated_methods).empty_param_method.ret_type, loc); } en.location = loc; AddError(new CanNotConvertTypes(en, en.type, to, loc)); } #if (DEBUG) check_operator(pct.first.convertion_method); #endif type_node conv_type = en.type; expression_node expr = create_simple_function_call(pct.first.convertion_method, en.location, en); expr.conversion_type = conv_type; return expr; } public static function_node get_empty_conversion(type_node from_type, type_node to_type, bool with_compile_time_executor) { basic_function_node bfn = null; bfn = new basic_function_node(SemanticTree.basic_function_type.none, to_type, false); bfn.parameters.AddElement(new basic_parameter("expr", from_type, SemanticTree.parameter_type.value, bfn)); if (with_compile_time_executor) bfn.compile_time_executor = SystemLibrary.SystemLibrary.delegated_empty_method; return bfn; } public expression_node explicit_convert_type(expression_node from, type_node to) { if (from.type == to) { return from; } possible_type_convertions ptc = type_table.get_convertions(from.type, to, false); if (ptc.second != null) { AddError(new TwoTypeConversionsPossible(from, ptc.first, ptc.second)); } if (ptc.first != null) { type_node conv_type = from.type; expression_node ret = create_simple_function_call(ptc.first.convertion_method, from.location, from); if ((ret is base_function_call)) (ret as base_function_call).IsExplicitConversion = true; ret.type = to; if (ptc.first.convertion_method is basic_function_node) ret.conversion_type = conv_type; return ret; } if ((type_table.is_derived(from.type, to)) || (type_table.is_derived(to, from.type)) || from.type.IsInterface || to.IsInterface && !(from.type is delegated_methods)) { if (from.type.IsSealed && to.IsInterface && !from.type.ImplementingInterfaces.Contains(to) || from.type.IsInterface && to.IsSealed && !to.ImplementingInterfaces.Contains(from.type)) { AddError(from.location, "CAN_NOT_EXPLICITLY_CONVERT_TYPE_{0}_TO_TYPE_{1}", from.type.PrintableName, to.PrintableName); } type_node conv_type = from.type; expression_node expr = create_simple_function_call(SystemLibrary.SystemLibrary.obj_to_obj, from.location, from); //TODO: Переделать. ((base_function_call)expr).ret_type = to; ((base_function_call)expr).conversion_type = conv_type; ((base_function_call)expr).IsExplicitConversion = true; return expr; } AddError(from.location, "CAN_NOT_EXPLICITLY_CONVERT_TYPE_{0}_TO_TYPE_{1}", from.type.PrintableName, to.PrintableName); return null; } public expression_node convert_type_to_bool(expression_node en) { return (convert_type(en,SystemLibrary.SystemLibrary.bool_type)); } public int convert_type_to_int_constant(expression_node en, out bool success) { success = true; if (en is int_const_node) return (en as int_const_node).constant_value; else if (en is byte_const_node) return (en as byte_const_node).constant_value; else if (en is sbyte_const_node) return (en as sbyte_const_node).constant_value; else if (en is short_const_node) return (en as short_const_node).constant_value; else if (en is ushort_const_node) return (en as ushort_const_node).constant_value; else if (en is uint_const_node) return (int)(en as uint_const_node).constant_value; else if (en is long_const_node) return (int)(en as long_const_node).constant_value; else if (en is ulong_const_node) return (int)(en as ulong_const_node).constant_value; success = false; return -1; } private int arr_nums = 0; private string get_temp_arr_name() { arr_nums++; return ("$intarr"+arr_nums); } //проверки на константные параметры internal static bool check_for_constant_or_readonly(expression_node ex, out bool flag, out general_node_type gnd) { gnd = general_node_type.expression; flag = true; switch (ex.semantic_node_type) { case semantic_node_type.array_const: case semantic_node_type.bool_const_node: case semantic_node_type.byte_const_node: case semantic_node_type.char_const_node: case semantic_node_type.class_constant_definition: case semantic_node_type.compiled_class_constant_definition: case semantic_node_type.namespace_constant_definition: case semantic_node_type.namespace_constant_reference: flag = true; return true; case semantic_node_type.class_field_reference: class_field_reference cfr = ex as class_field_reference; if (cfr.field.IsReadOnly) { flag = false; gnd = general_node_type.variable_node; return true; } return check_for_constant_or_readonly(cfr.obj,out flag,out gnd); case semantic_node_type.static_compiled_variable_reference: static_compiled_variable_reference scvr = ex as static_compiled_variable_reference; if (scvr.var.IsReadOnly) { flag = false; gnd = general_node_type.variable_node; return true; } else if (scvr.var.IsLiteral) { flag = true; gnd = general_node_type.variable_node; return true; } return false; case semantic_node_type.compiled_variable_reference: compiled_variable_reference cvr = ex as compiled_variable_reference; if (cvr.var.IsReadOnly) { flag = false; gnd = general_node_type.variable_node; return true; } else if (cvr.var.IsLiteral) { flag = true; gnd = general_node_type.variable_node; return true; } if (cvr.obj != null) return check_for_constant_or_readonly(cvr.obj,out flag,out gnd); return false; case semantic_node_type.common_parameter_reference: common_parameter_reference cpr = ex as common_parameter_reference; flag = true; return (cpr.par.concrete_parameter_type == concrete_parameter_type.cpt_const); case semantic_node_type.simple_array_indexing: simple_array_indexing sai = ex as simple_array_indexing; return check_for_constant_or_readonly(sai.simple_arr_expr,out flag,out gnd); default: return false; } } //производит проверку для неопределённых типов internal bool possible_equal_types(type_node t1, type_node t2) { if (t1 == t2) { return true; } /*var comptn1 = t1 as compiled_type_node; var comptn2 = t2 as compiled_type_node; if (comptn1 != null && comptn2 != null) { if (comptn1.compiled_type == comptn2.compiled_type) // увы - тут типы Type разные и хеш-коды у них разные return true; } */ if (!t1.depended_from_indefinite && !t2.depended_from_indefinite) { return false; } if (t1.semantic_node_type == semantic_node_type.indefinite_type || t2.semantic_node_type == semantic_node_type.indefinite_type) { return true; } common_type_node ctn1 = t1 as common_type_node; common_type_node ctn2 = t2 as common_type_node; if (ctn1 == null || ctn2 == null || ctn1.original_template == null || ctn2.original_template == null || ctn1.original_template != ctn2.original_template) { return false; } List types1 = ctn1.original_template.GetParamsList(ctn1); List types2 = ctn2.original_template.GetParamsList(ctn2); int count = types1.Count; if (count != types2.Count) { return false; } bool eq = true; for (int i = 0; i < count; i++) { eq = possible_equal_types(types1[i], types2[i]); if (!eq) break; } return eq; } /// /// Возвращает список преобразований типов для вызова метода. /// /// Список фактических параметров. /// Список формальных параметров. /// Для единственного метода у которого типы параметров совпадают, но в качестве var параметра мы передаем константное значение мы можем сгенерировать более подробное сообщение об ошибке. /// Список преобразований типов. internal possible_type_convertions_list get_conversions(expressions_list factparams, parameter_list formalparams,bool is_alone_method_defined, location locg, out Errors.Error error) { //TODO:Явно указывать capacity при создании. possible_type_convertions_list tc = new possible_type_convertions_list(); error = null; possible_type_convertions ptc; if (factparams.Count>formalparams.Count) { if ( (formalparams.Count==0) || (!(formalparams[formalparams.Count-1].is_params)) ) { return null; } } type_node for_par_type = null; array_internal_interface aii=null; if (formalparams.Count > 0) { parameter pr=formalparams[formalparams.Count - 1]; if (pr.is_params && //это для возможности вызова сразу с массивом[], типа просто не обращаем внимаение на params !(factparams.Count == formalparams.Count && factparams[factparams.Count - 1].type == formalparams[formalparams.Count - 1].type)) { //TODO: Добавить проверку на правильность. aii = (array_internal_interface) pr.type.get_internal_interface(internal_interface_kind.unsized_array_interface); for_par_type = aii.element_type; tc.snl = new statement_node_list(); location loc=null; if (factparams.Count > 0) loc = factparams[factparams.Count-1].location; //var_definition_node vdn=syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(),loc); var_definition_node vdn = null; if (syntax_tree_visitor.context.converted_func_stack.size > 0) { common_function_node cfn = syntax_tree_visitor.context.converted_func_stack.first(); if (cfn.is_generic_function || !syntax_tree_visitor.context.has_nested_functions && syntax_tree_visitor.context.converted_func_stack.size == 1) { vdn = syntax_tree_visitor.context.add_var_definition(get_temp_arr_name(), loc); } else if (syntax_tree_visitor.context.converted_type != null) vdn = syntax_tree_visitor.context.add_field(get_temp_arr_name(), loc, pr.type, polymorphic_state.ps_static); else vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc); } else if (syntax_tree_visitor.context.converted_type != null) vdn = syntax_tree_visitor.context.add_field(get_temp_arr_name(), loc, pr.type, polymorphic_state.ps_static); else vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc); syntax_tree_visitor.context.close_var_definition_list(pr.type,null); expression_node fst=null; /*switch (syntax_tree_visitor.context.converting_block()) { case block_type.function_block: { fst=new local_variable_reference((local_variable)vdn,0,loc); break; } case block_type.namespace_block: { fst=new namespace_variable_reference((namespace_variable)vdn,loc); break; } }*/ switch (vdn.semantic_node_type) { case semantic_node_type.local_variable: { fst = new local_variable_reference((local_variable)vdn, 0, loc); break; } case semantic_node_type.namespace_variable: { fst = new namespace_variable_reference((namespace_variable)vdn, loc); break; } case semantic_node_type.local_block_variable: { fst = new local_block_variable_reference((local_block_variable)vdn, loc); break; } case semantic_node_type.class_field: { class_field cf = vdn as class_field; cf.polymorphic_state = polymorphic_state.ps_static; fst = new static_class_field_reference(cf, loc); break; } default: throw new CompilerInternalError("Invalid node type"); } tc.var_ref = fst; int del=factparams.Count-formalparams.Count+1; int_const_node icn=new int_const_node(del,loc); expression_node bfc = create_simple_function_call(SystemLibrary.SystemLibrary.resize_func, loc, fst, icn); tc.snl.AddElement(bfc); /*if (factparams.Count == 0) { possible_type_convertions ptci=new possible_type_convertions(); ptci.first=null; ptci.second=null; ptci.from=null; ptci.to = for_par_type; tc.AddElement(ptci); }*/ } } for(int i=0;i= formalparams.Count-1)) { formal_param_type = for_par_type; } else { formal_param_type = formalparams[i].type; } if (possible_equal_types(factparams[i].type, formal_param_type)) { if ((i= formalparams.Count - 1)) { expression_node to = new simple_array_indexing(tc.var_ref,//factparams[formalparams.Count - 1], new int_const_node(i - formalparams.Count + 1, factparams[i].location), aii.element_type, factparams[i].location); expression_node from = factparams[i]; statement_node stat = syntax_tree_visitor.find_operator(compiler_string_consts.assign_name, to, from, factparams[i].location); tc.snl.AddElement(stat); } continue; } if ((i= formalparams.Count - 1)) { expression_node to = new simple_array_indexing(tc.var_ref,//factparams[formalparams.Count - 1], new int_const_node(i - formalparams.Count + 1, factparams[i].location), aii.element_type, factparams[i].location); expression_node from = factparams[i]; statement_node stat = syntax_tree_visitor.find_operator(compiler_string_consts.assign_name, to, from, factparams[i].location); tc.snl.AddElement(stat); } } else { if (is_alone_method_defined) { //issue #348 if (formal_param_type == SystemLibrary.SystemLibrary.object_type && factparams[i].type is delegated_methods) { possible_type_convertions ptci = new possible_type_convertions(); ptci.first = null; ptci.second = null; ptci.from = factparams[i].type; ptci.to = formal_param_type; tc.AddElement(ptci); factparams[i] = syntax_tree_visitor.CreateDelegateCall((factparams[i].type as delegated_methods).proper_methods[0]); return tc; } else error = new CanNotConvertTypes(factparams[i], factparams[i].type, formal_param_type, locg); } return null; } } else { tc.AddElement(ptc); if ((for_par_type != null) && (i >= formalparams.Count - 1)) { expression_node to = new simple_array_indexing(tc.var_ref,//factparams[formalparams.Count - 1], new int_const_node(i - formalparams.Count + 1, factparams[i].location), aii.element_type, factparams[i].location); expression_node from = create_simple_function_call(ptc.first.convertion_method, factparams[i].location, factparams[i]); statement_node stat = syntax_tree_visitor.find_operator(compiler_string_consts.assign_name, to, from, factparams[i].location); tc.snl.AddElement(stat); } } } } if (tc.snl != null) foreach (statement_node sn in tc.snl) sn.location = null; return tc; } private simple_array_indexing make_unmanaged_string_getter(compiled_function_call cfc) { return new simple_array_indexing(cfc.obj, cfc.parameters[0], SystemLibrary.SystemLibrary.char_type, cfc.location); } private simple_array_indexing make_unmanaged_shortstring_getter(base_function_call cfc) { return new simple_array_indexing(cfc.parameters[0], cfc.parameters[1], SystemLibrary.SystemLibrary.char_type, cfc.location); } private bool is_string_getter(expression_node en) { if (en is common_namespace_function_call && (en as common_namespace_function_call).function_node == SystemLibrary.SystemLibInitializer.GetCharInShortStringProcedure.sym_info) { return true; } else if (en is compiled_static_method_call && (en as compiled_static_method_call).function_node == SystemLibrary.SystemLibInitializer.GetCharInShortStringProcedure.sym_info) { return true; } else if (en is compiled_function_call) { if ((en as compiled_function_call).function_node.cont_type != SystemLibrary.SystemLibrary.string_type) return false; if ((en as compiled_function_call).function_node.name.StartsWith("get_")) return true; } return false; } private enum method_compare {less_method,greater_method,not_comparable_methods}; private enum type_conversion_compare {less_type_conversion,greater_type_conversion,equal_type_conversions}; private type_conversion_compare compare_type_conversions(possible_type_convertions left,possible_type_convertions right) { if ((left.first==null)&&(right.first!=null)) { return type_conversion_compare.greater_type_conversion; } if ((left.first!=null)&&(right.first==null)) { return type_conversion_compare.less_type_conversion; } if ((left.first != null) && (right.first != null)) { convert_types_function_node cleft = left.first.convertion_method as convert_types_function_node; convert_types_function_node cright = right.first.convertion_method as convert_types_function_node; if ((cleft != null) && (cright != null)) { if ((cleft.Good) && (!cright.Good)) { return type_conversion_compare.greater_type_conversion; } if ((!cleft.Good) && (cright.Good)) { return type_conversion_compare.less_type_conversion; } } } /*if ((left.first==null)&&(right.first==null)) { return type_conversion_compare.equal_type_conversions; }*/ //type_compare tc=type_table.compare_types(left.first.to,right.first.to); type_compare tc=type_table.compare_types(left.to,right.to); if (tc==type_compare.greater_type) { if (left.to.type_special_kind == type_special_kind.diap_type && left.to is common_type_node && right.to.type_special_kind == type_special_kind.diap_type && right.to is common_type_node) { tc = type_table.compare_types(left.to.base_type,right.to.base_type); if (tc == type_compare.greater_type) return type_conversion_compare.less_type_conversion; } else return type_conversion_compare.less_type_conversion; //return type_conversion_compare.greater_type_conversion; } if (tc==type_compare.less_type) { if (left.to.type_special_kind == type_special_kind.diap_type && left.to is common_type_node && right.to.type_special_kind == type_special_kind.diap_type && right.to is common_type_node) { tc = type_table.compare_types(left.to.base_type,right.to.base_type); if (tc == type_compare.less_type) return type_conversion_compare.greater_type_conversion; } else return type_conversion_compare.greater_type_conversion; //return type_conversion_compare.less_type_conversion; } internal_interface left_del = left.to.get_internal_interface(internal_interface_kind.delegate_interface); internal_interface right_del = right.to.get_internal_interface(internal_interface_kind.delegate_interface); if ((left_del == null) && (right_del == null)) { return type_conversion_compare.equal_type_conversions; } if ((left_del == null) && (right_del != null)) { return type_conversion_compare.less_type_conversion; } if ((left_del != null) && (right_del == null)) { return type_conversion_compare.greater_type_conversion; } return type_conversion_compare.equal_type_conversions; } private method_compare compare_methods(function_node left_func, function_node right_func, possible_type_convertions_list left,possible_type_convertions_list right) { function_compare fc = function_node.compare_functions(left_func, right_func); if (fc == function_compare.less) { return method_compare.less_method; } if (fc == function_compare.greater) { return method_compare.greater_method; } bool left_greater=false; bool right_greater=false; for(int i=0;i right_func.generic_parameters_count) return method_compare.greater_method; else if (left_func.generic_parameters_count < right_func.generic_parameters_count) return method_compare.less_method; else // SSM 8/8/15 Два метода одинаковы по всем параметрам, но у одного - больше instance_params, т.е. он менее специализирован if (left_func.parameters.Count == right_func.parameters.Count) { bool eq = true; for (var i=0; i rc) return method_compare.less_method; // Тут совпадать они не могут, но если совпадают - пусть уж будут несравнимыми } } } return method_compare.not_comparable_methods; } //DS добавил этот метод //А так ли это надо делать? //Сергей, может ты знаеш? internal static bool eq_type_nodes(type_node tn1, type_node tn2, bool strong) { if (tn1 == tn2) return true; if (tn1 == null || tn2 == null) { return false; } if (tn1 is lambda_any_type_node || tn2 is lambda_any_type_node) //lroman// Считаем, что тип lambda_any_type_node равен всем типам. Это используется при выводе параметров лямбды return true; if (tn1.generic_function_container != null && tn2.generic_function_container != null) { if (strong && tn1.generic_function_container != tn2.generic_function_container) { return false; } return (tn1.generic_param_index == tn2.generic_param_index); } if (tn1.type_special_kind != tn2.type_special_kind) { return false; } switch (tn1.type_special_kind) { case type_special_kind.array_kind: case type_special_kind.set_type: case type_special_kind.typed_file: if (tn1.type_special_kind == type_special_kind.array_kind) { if (tn1 is compiled_type_node && tn2 is compiled_type_node && (tn1 as compiled_type_node).rank != (tn2 as compiled_type_node).rank) return false; if (tn1 is common_type_node && tn2 is common_type_node && (tn1 as common_type_node).rank != (tn2 as common_type_node).rank) return false; } return eq_type_nodes(tn1.element_type, tn2.element_type, strong); } ref_type_node rtn1 = tn1 as ref_type_node; if (rtn1 != null) { ref_type_node rtn2 = tn2 as ref_type_node; if (rtn2 == null) { return false; } return eq_type_nodes(rtn1.pointed_type, rtn2.pointed_type, strong); } if (tn1.is_generic_type_definition && tn2.is_generic_type_instance || tn2.is_generic_type_definition && tn1.is_generic_type_instance) { type_node tdef, tinst; if (tn1.is_generic_type_definition) { tdef = tn1; tinst = tn2; } else { tdef = tn2; tinst = tn1; } if (tinst.original_generic != tdef) { return false; } if (tdef is common_type_node) { common_type_node ctdef = tdef as common_type_node; int count = ctdef.generic_params.Count; for (int i = 0; i < count; ++i) { if (ctdef.generic_params[i] != tinst.instance_params[i]) { return false; } } } else if (tdef is compiled_type_node) { compiled_type_node ctdef = tdef as compiled_type_node; int count = ctdef.generic_params.Count; for (int i = 0; i < count; ++i) { if (ctdef.generic_params[i] != tinst.instance_params[i]) { return false; } } } return true; } if (tn1.is_generic_type_instance) { if (!tn2.is_generic_type_instance) { return false; } if (tn1.original_generic != tn2.original_generic) { return false; } int count = tn1.instance_params.Count; for (int i = 0; i < count; ++i) { if (!eq_type_nodes(tn1.instance_params[i], tn2.instance_params[i], strong)) { return false; } } return true; } if (tn1.get_internal_interface(internal_interface_kind.delegate_interface) != null) { if (strong) return tn1 == tn2; delegate_internal_interface d1 = tn1.get_internal_interface(internal_interface_kind.delegate_interface) as delegate_internal_interface; delegate_internal_interface d2 = tn2.get_internal_interface(internal_interface_kind.delegate_interface) as delegate_internal_interface; if (d2 != null) return function_eq_params_and_result(d1.invoke_method, d2.invoke_method); } return false; } internal static bool eq_type_nodes(type_node tn1, type_node tn2) { return eq_type_nodes(tn1, tn2, false); } //Этот метод сверяет не только параметры, но и возвращаемое значение public static bool function_eq_params_and_result(function_node left, function_node right, bool weak = false) { if (!function_eq_params(left, right, weak)) { return false; } else { return eq_type_nodes(left.return_value_type, right.return_value_type, weak); } } //Сравниваем типы-параметры generic-функций public static bool function_eq_generic_params(function_node left, function_node right) { List left_type_params = left.get_generic_params_list(); List right_type_params = right.get_generic_params_list(); if (left_type_params == null && right_type_params == null) { return true; } if (left_type_params == null || right_type_params == null) { return false; } if (left_type_params.Count != right_type_params.Count) { return false; } for (int i = 0; i < left_type_params.Count; i++) { if (string.Compare(left_type_params[i].name, right_type_params[i].name, true) != 0) { return false; } } return true; } public static bool function_eq_params(function_node left, function_node right) { return function_eq_params(left, right, true); } public static bool function_eq_params(function_node left, function_node right, bool compare_parameter_types) { if (compare_parameter_types) { if (!function_eq_generic_params(left, right)) { return false; } } else { if (left.generic_parameters_count != right.generic_parameters_count) { return false; } } if (left.parameters.Count != right.parameters.Count) { return false; } for (int i = 0; i < left.parameters.Count; i++) { if (!eq_type_nodes(left.parameters[i].type,right.parameters[i].type) || compare_parameter_types && left.parameters[i].parameter_type != right.parameters[i].parameter_type) { return false; } } return true; } private void check_single_possible_convertion(ILocation loc,possible_type_convertions_list ptcal) { foreach(possible_type_convertions ptc in ptcal) { if (ptc.second!=null) { AddError(new PossibleTwoTypeConversionsInFunctionCall(loc,ptc.first,ptc.second)); } } } private void convert_function_call_expressions(function_node fn,expressions_list exprs, possible_type_convertions_list ptcal) { for(int i=0;i= fn.parameters.Count - 1)) { //statement_list_stack.top().statements.AddRange(ptcal.snl); statements_expression_node sre = new statements_expression_node(ptcal.snl, ptcal.var_ref, ptcal.var_ref.location); exprs.remove_range(fn.parameters.Count - 1, exprs.Count - fn.parameters.Count); //exprs.AddElement(ptcal.var_ref); //exprs[i] = ptcal.var_ref; exprs[i] = sre; break; } if ((ptcal[i]==null)||(ptcal[i].first==null)||exprs[i] is null_const_node) { continue; } expression_node[] temp_arr = new expression_node[1]; temp_arr[0] = exprs[i]; if (ptcal[i].first.convertion_method is compiled_constructor_node) exprs[i] = create_compiled_construcor_call(ptcal[i].first.convertion_method as compiled_constructor_node, get_location(exprs[i]), temp_arr); else exprs[i] = create_simple_function_call(ptcal[i].first.convertion_method, get_location(exprs[i]), temp_arr); } //TODO: Можно сделать параметры по умолчанию для откомпилированных функций. if ((exprs.Count < fn.parameters.Count) && (fn.node_kind == SemanticTree.node_kind.common)) { if (!(fn is common_namespace_function_node && (fn as common_namespace_function_node).ConnectedToType != null) && fn.parameters != null && fn.parameters.Count - 1 == exprs.Count && fn.parameters[fn.parameters.Count-1].is_params || fn is common_namespace_function_node && (fn as common_namespace_function_node).ConnectedToType != null && fn.parameters != null && fn.parameters.Count - 1 == exprs.Count && fn.parameters[fn.parameters.Count - 1].is_params) { statements_expression_node sre = new statements_expression_node(ptcal.snl, ptcal.var_ref, ptcal.var_ref.location); //exprs.remove_range(fn.parameters.Count - 1, exprs.Count - fn.parameters.Count); //exprs.AddElement(ptcal.var_ref); //exprs[i] = ptcal.var_ref; exprs.AddElement(sre); } common_function_node cfn = (common_function_node)fn; for (int j = exprs.Count; j < cfn.parameters.Count; j++) { common_parameter cp = (common_parameter)cfn.parameters[j]; if (cp.default_value != null) exprs.AddElement(cp.default_value); } } else if ((exprs.Count < fn.parameters.Count) && (fn.node_kind == SemanticTree.node_kind.compiled)) { if (!(fn is compiled_function_node && (fn as compiled_function_node).ConnectedToType != null) && fn.parameters != null && fn.parameters.Count - 1 == exprs.Count && fn.parameters[fn.parameters.Count - 1].is_params || fn is compiled_function_node && (fn as compiled_function_node).ConnectedToType != null && fn.parameters != null && fn.parameters.Count - 1 == exprs.Count && fn.parameters[fn.parameters.Count - 1].is_params) { statements_expression_node sre = new statements_expression_node(ptcal.snl, ptcal.var_ref, ptcal.var_ref.location); exprs.AddElement(sre); } //compiled_function_node cfn = (compiled_function_node)fn; for (int j = exprs.Count; j < fn.parameters.Count; j++) { compiled_parameter cp = (compiled_parameter)fn.parameters[j]; if (cp.default_value != null) exprs.AddElement(cp.default_value); } } } private function_node find_eq_return_value_method_in_list(function_node fn, function_node_list funcs) { foreach (function_node f in funcs) { //Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть. if (f == fn) { return f; } if (function_eq_params_and_result(fn,f)) { if (fn.original_function == f.original_function) { return f; } } } return null; } public function_node find_eq_method_in_list(function_node fn,function_node_list funcs) { foreach(function_node f in funcs) { //Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть. if (f==fn) { return f; } if (function_eq_params(fn, f)) { if (fn.original_function == f.original_function) { return f; } } } return null; } public function_node is_exist_eq_method_in_list(function_node fn, function_node_list funcs) { return find_eq_return_value_method_in_list(fn, funcs); } public void init_reference_type(type_node ctn) { SystemLibrary.SystemLibrary.init_reference_type(ctn); } /// /// Получение compiled_type_node из либо compiled_type_node либо compiled_generic_instance_type_node. Используется ниже локально /// private compiled_type_node get_compiled_type_node(type_node t) { var ctn = t as compiled_type_node; if (ctn == null) { var cgn = t as compiled_generic_instance_type_node; if (cgn != null) ctn = cgn.original_generic as compiled_type_node; } return ctn; } //Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов. public function_node select_function(expressions_list parameters, List functions, location loc, List syntax_nodes_parameters = null, bool only_from_not_extensions = false) { if (functions == null) { return AddError(new NoFunctionWithThisName(loc)); } function_node_list set_of_possible_functions = new function_node_list(); bool is_alone_method_defined = (functions.Count() == 1); function_node first_function = functions.FirstOrDefault().sym_info as function_node; bool _is_assigment = first_function.name == compiler_string_consts.assign_name; basic_function_node _tmp_bfn = functions.FirstOrDefault().sym_info as basic_function_node; List indefinits = new List(); foreach (SymbolInfo function in functions) { // В режиме only_from_not_extensions пропускать все extensions if (only_from_not_extensions && (function.sym_info is function_node) && (function.sym_info as function_node).is_extension_method) continue; #if (DEBUG) if (function.sym_info.general_node_type != general_node_type.function_node && function.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 (function.sym_info.general_node_type == general_node_type.property_node) { fn = (function.sym_info as property_node).get_function; } else fn = (function_node)function.sym_info; if (fn.node_kind == node_kind.indefinite) { indefinits.Add(fn); } else if (fn.node_kind == 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) { 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); } 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; } 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) { 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)) // SSM 6.08.18 - так просто исправить не получается - видимо, сопоставление параметров работает неверно else if ((parameters.Count == fn.parameters.Count - 1) && fn.parameters[fn.parameters.Count-1].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); else if (parameters.Count == 1 && fn is compiled_function_node && (fn as compiled_function_node).ConnectedToType != null && fn.parameters.Count == 2 && fn.parameters[1].is_params) if (!set_of_possible_functions.Contains(fn)) set_of_possible_functions.AddElement(fn); } if (set_of_possible_functions.Count == 0 && indefinits.Count == 0) { return 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, syntax_tree_visitor.context, 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; } catch(Errors.Error err) { return AddError(err); } } } 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) { return 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++) { Errors.Error err = null; possible_type_convertions_list tc = get_conversions(parameters, set_of_possible_functions[i].parameters, is_alone_method_defined, loc, out err); if (err != null) return AddError(err); //fix dlja lambd i extension metodov (c->c.IsDigit) if (tc == null) { expressions_list el = new expressions_list(); el.AddRange(parameters); bool has_lambda_var = false; for (int k = 0; k < el.Count; k++) { if (el[k] is local_variable_reference && el[k].type is delegated_methods && (el[k].type as delegated_methods).empty_param_method != null) { el[k].type = (el[k].type as delegated_methods).empty_param_method.ret_type; has_lambda_var = true; } } if (has_lambda_var) { err = null; tc = get_conversions(el, set_of_possible_functions[i].parameters, is_alone_method_defined, loc, out err); if (err != null) return AddError(err); } } 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) return AddError(new CanNotConvertTypes(parameters[1], parameters[1].type, parameters[0].type, parameters[1].location)); if (_tmp_bfn != null && parameters.Count == 2) return AddError(new OperatorCanNotBeAppliedToThisTypes(_tmp_bfn.name, parameters[0], parameters[1], loc)); return 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 (SystemLibrary.SystemLibInitializer.InSetProcedure != null) { if (set_of_possible_functions[j] == SystemLibrary.SystemLibInitializer.InSetProcedure.sym_info) { mc = method_compare.less_method; } else if (set_of_possible_functions[i] == SystemLibrary.SystemLibInitializer.InSetProcedure.sym_info) { mc = method_compare.greater_method; } } 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++; } } //Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений //в дальнейшем может вызвать странное поведение, это надо проверить 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); } SortedDictionary> distances = new SortedDictionary>(); function_node best_function = null; List to_remove = new List(); foreach (function_node fn in set_of_possible_functions) { if (fn.return_value_type != null) { if (best_function == null) { best_function = fn; } else { type_compare tc = type_table.compare_types(best_function.return_value_type, fn.return_value_type); if (best_function.return_value_type.is_standard_type && fn.return_value_type.is_standard_type) { if (tc == type_compare.less_type) { to_remove.Add(best_function); best_function = fn; } else if (tc == type_compare.greater_type) to_remove.Add(fn); } else { if (tc == type_compare.greater_type) { to_remove.Add(best_function); best_function = fn; } else if (tc == type_compare.less_type) to_remove.Add(fn); } } } } foreach (function_node fn in to_remove) { set_of_possible_functions.remove(fn); } // Формирование словаря списков функций с одинаковым значением расстояния // SSM 07/11/17 Для a.Average(x->x) - остаётся 4 функции. На этом уровне выбрать невозможно: // Average(IEnumerable,integer->real): real // Average(IEnumerable,integer->int64): real // Average(IEnumerable,integer->Nullable): real // Average(IEnumerable,integer->integer): real // Дело в том, что на этом уровне лямбда x->x имеет тип lambda_anytype->lambda_anytype. Все подходят :) foreach (function_node fn in set_of_possible_functions) { int distance = 0; for (int i = 0; i < parameters.Count; i++) { type_node from = parameters[i].type; type_node to = fn.parameters[Math.Min(i, fn.parameters.Count - 1)].type; if (fn.parameters[Math.Min(i, fn.parameters.Count - 1)].is_params) to = to.element_type; // ToDo: необходимо сделать более детальную get_type_distance. // Сейчас для функциональных параметров она всегда возвращает 1000 distance += get_type_distance(from, to); } /*if (fn.return_value_type != null) { if (fn.return_value_type.is_generic_type_instance || fn.return_value_type.is_generic_type_definition) distance += 2; else if (fn.return_value_type == SystemLibrary.SystemLibrary.object_type) distance += 3; else distance += 1; }*/ List lst; if (distances.TryGetValue(distance, out lst)) { lst.Add(fn); } else { lst = new List(); lst.Add(fn); distances[distance] = lst; } } foreach (int dist in distances.Keys) // Дистанции упорядочены по возрастанию. Логика тут немного странная: // если для какой-то минимальной дистанции найдется ровно одна функция, то она и выбирается // если две и больше - то они пробрасываются и мы переходим к бОльшей дистанции { List funcs = distances[dist]; if (funcs.Count == 1) { Errors.Error err = null; possible_type_convertions_list tcl = get_conversions(parameters, funcs[0].parameters, true, loc, out err); if (err != null) return AddError(err); convert_function_call_expressions(funcs[0], parameters, tcl); return funcs[0]; } Func IsFunc = t => t.IsGenericType && t.FullName.StartsWith("System.Func"); Func get_type = tt => { var ct = get_compiled_type_node(tt); return ct?.compiled_type; }; Func IsFuncT = tt => { var ct = get_compiled_type_node(tt); if (ct == null) return false; Type t = ct.compiled_type; return IsFunc(t); }; var ParamsCount = funcs[0].parameters.Count; var b = funcs.All(f => f.parameters.Count == ParamsCount); if (!b) break; var bools = Enumerable.Range(1, funcs.Count()).Select(x => true).ToList(); var AllOK = true; for (var i=0; i < ParamsCount; i++) { // Хочу взять проекцию всех функций на i-тый параметр var parsi = funcs.Select(f => f.parameters[i].type); if (parsi.Any(p => !IsFuncT(p))) // Если какой-то параметр не функция, то пробросим его continue; var argss = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()).ToArray(); // последовательность массивов параметров Func var cnts = argss.Select(a => a.Count()); var fpi = funcs[0].parameters[i]; var cnt = get_type(fpi.type).GetGenericArguments().Count(); // Проверю, что у остальных функций столько же параметров if (cnts.Any(c => c != cnts.First())) // если нет, то - всё - это ошибка - многозначность. Хотя тут уже не должно быть { AllOK = false; break; } // Цикл по параметрам Func кроме последнего for (var k = 0; k < cnt - 1; k++) { var kpars = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()[k]); Type p0 = kpars.First(); bool bb = kpars.All(p => p.Equals(p0)); if (!bb) { AllOK = false; break; } } if (!AllOK) break; var kres = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()[cnt - 1]).ToArray(); //if (funcs[0].is_extension_method) var fldiResType = funcs[0].is_extension_method ? // странно, но всегда кво параметров в syntax_nodes_parameters на 1 меньше. Иначе падает ((syntax_nodes_parameters[i - 1] as SyntaxTree.function_lambda_definition).RealSemTypeOfResult as compiled_type_node).compiled_type : ((syntax_nodes_parameters[i - 1] as SyntaxTree.function_lambda_definition).RealSemTypeOfResult as compiled_type_node).compiled_type; for (int n = 0; n < bools.Count; n++) { if (!fldiResType.Equals(kres[n])) bools[n] = false; } //var rettype_i = } if (AllOK) if (bools.Count(x=>x==true) == 1) // урра! нашлась ровно одна функция! мы победили! { var ind = bools.IndexOf(true); return funcs[ind]; } /// Проба 15.01.18 - потом удалить /*{ var f1 = funcs[0]; var f2 = funcs[1]; for (int i = 0; i < parameters.Count; i++) { type_node f1i = f1.parameters[i].type; type_node f2i = f2.parameters[i].type; var f1ic = get_compiled_type_node(f1i); var f2ic = get_compiled_type_node(f2i); if (f1ic == null || f2ic == null) break; Type ct1 = f1ic.compiled_type; Type ct2 = f2ic.compiled_type; if (IsFunc(ct1) && IsFunc(ct2)) { var l1 = ct1.GetGenericArguments()[0]; var l2 = ct2.GetGenericArguments()[0]; var b = l1.Equals(l2); var b1 = l1 == l2; } //var p = syntax_nodes_parameters[i]; } }*/ // Вот здесь нужен анализ всех оставшихся функций. // Если они отличаются только функциональными параметрами и у этих параметров // одинаковый тип параметров (они уже инстанцированы!), то надо еще раз // вызвать то, что вызывается в DeduceFunction чтобы установить, каков тип возвращаемого значения лямбды, после чего // выбрать либо функцию из оставшихся с ровно совпадающим типом лямбды либо с ближайшим // (остались только те, к которым можно преобразовать) // Некоторая проблема будет если лямбд останется несколько и расстояния до результата будут разными и ненулевыми везде if (funcs.Count >= 2) // SSM - это ужасный способ устранения бага #236 Range(1,10).Sum(e -> e); Для хорошего способа весь код выбора версий функций для делегатов надо переписывать { var f1 = funcs[0]; var f2 = funcs[1]; if (f1.parameters.Count == f2.parameters.Count) { for (var i = 0; i < f1.parameters.Count; i++) { var p1 = f1.parameters[i].type; var p2 = f2.parameters[i].type; // типы у них должны начинаться на Func, надо посмотреть тип последнего параметра, // и если это Nullable, то исключить его из рассмотрения // Напоминаю, что p1 и p2 если это Func, то могут быть // либо compiled_type_node (List) либо compiled_generic_instance_type_node (List) var ctn1 = p1 as compiled_type_node; if (ctn1 == null) { var cgn1 = p1 as compiled_generic_instance_type_node; if (cgn1 != null) ctn1 = cgn1.original_generic as compiled_type_node; } var ctn2 = p2 as compiled_type_node; if (ctn2 == null) { var cgn2 = p2 as compiled_generic_instance_type_node; if (cgn2 != null) ctn2 = cgn2.original_generic as compiled_type_node; } if (ctn1 == null || ctn2 == null) continue; System.Type ct1 = ctn1.compiled_type; if (ct1.IsGenericType && ct1.FullName.StartsWith("System.Func")) { var c = ct1.GetGenericArguments().Length; if (c != 0 && (ct1.GetGenericArguments().Last().FullName == null || ct1.GetGenericArguments().Last().FullName.StartsWith("System.Nullable"))) return f2; } System.Type ct2 = ctn2.compiled_type; if (ct2.IsGenericType && ct2.FullName.StartsWith("System.Func")) { var c = ct2.GetGenericArguments().Length; if (c != 0 && (ct2.GetGenericArguments().Last().FullName == null || ct2.GetGenericArguments().Last().FullName.StartsWith("System.Nullable"))) return f1; } } /*if (f1.return_value_type != null && f2.return_value_type != null) { var p1 = f1.return_value_type; var p2 = f2.return_value_type; var ctn1 = p1 as compiled_type_node; if (ctn1 == null) { var cgn1 = p1 as compiled_generic_instance_type_node; if (cgn1 != null) ctn1 = cgn1.original_generic as compiled_type_node; } var ctn2 = p2 as compiled_type_node; if (ctn2 == null) { var cgn2 = p2 as compiled_generic_instance_type_node; if (cgn2 != null) ctn2 = cgn2.original_generic as compiled_type_node; } if (ctn1 == null || ctn2 == null) continue; System.Type ct1 = ctn1.compiled_type; if (ct1.IsGenericType && ct1.FullName.StartsWith("System.Func")) { var c = ct1.GetGenericArguments().Length; if (c != 0 && ct1.GetGenericArguments().Last().FullName.StartsWith("System.Nullable")) return f2; } System.Type ct2 = ctn2.compiled_type; if (ct2.IsGenericType && ct2.FullName.StartsWith("System.Func")) { var c = ct2.GetGenericArguments().Length; if (c != 0 && ct2.GetGenericArguments().Last().FullName.StartsWith("System.Nullable")) return f1; } }*/ } } } return AddError(new SeveralFunctionsCanBeCalled(loc, set_of_possible_functions)); } private int get_type_distance(type_node from, type_node to) { if (from == to) return 0; if (from is delegated_methods && (from as delegated_methods).empty_param_method != null && (from as delegated_methods).empty_param_method.ret_type != null) from = (from as delegated_methods).empty_param_method.ret_type; if (to is delegated_methods && (to as delegated_methods).empty_param_method != null && (to as delegated_methods).empty_param_method.ret_type != null) to = (to as delegated_methods).empty_param_method.ret_type; internal_interface from_ii = from.get_internal_interface(internal_interface_kind.delegate_interface); internal_interface to_ii = to.get_internal_interface(internal_interface_kind.delegate_interface); if (from_ii != null && to_ii != null) { delegate_internal_interface from_dii = (delegate_internal_interface)from_ii; if (to_ii != null) { delegate_internal_interface to_dii = (delegate_internal_interface)to_ii; if (from_dii.parameters.Count == to_dii.parameters.Count) { bool eq = TreeConverter.convertion_data_and_alghoritms.function_eq_params_and_result(from_dii.invoke_method, to_dii.invoke_method); if (eq) { return 0; } } } } else if (to_ii != null && from.semantic_node_type == semantic_node_type.delegated_method && (from as delegated_methods).proper_methods[0].ret_type is lambda_any_type_node) { delegate_internal_interface to_dii = (delegate_internal_interface)to_ii; if (to_dii.invoke_method.return_value_type != null) { to = to_dii.invoke_method.return_value_type; if (to == SystemLibrary.SystemLibrary.integer_type) return 94; else if (to == SystemLibrary.SystemLibrary.int64_type) return 96; else if (to == SystemLibrary.SystemLibrary.double_type) return 98; else return 1000; } } type_compare tc = type_table.compare_types(from, to); if (tc == type_compare.non_comparable_type) return 1000; if (!from.IsInterface && to.IsInterface) return 200; if (tc == type_compare.less_type) { return 100; } if (tc == type_compare.greater_type) return 300; return 1000; } private function_node is_exist_eq_return_value_method(function_node fn, function_node_list funcs) { fn = find_eq_return_value_method_in_list(fn, funcs); return fn; } private string get_return_variable_name(string function_name) { return (compiler_string_consts.function_return_value_prefix+function_name); } public void create_function_return_variable(common_function_node cfn, SymbolInfo ret_var) { if (!SemanticRules.AddResultVariable) return; //#if (DEBUG) if (cfn.return_value_type == null) { return; //throw new CompilerInternalError("Procedure can not return value"); } //#endif if (cfn.return_variable != null) { if (ret_var != null) ret_var.sym_info = cfn.return_variable; return; } cfn.return_variable = new local_variable(get_return_variable_name(cfn.name), cfn.return_value_type, cfn, cfn.loc); cfn.return_variable.inital_value = syntax_tree_visitor.context.GetInitalValueForVariable(cfn.return_variable, null); cfn.var_definition_nodes_list.AddElement(cfn.return_variable); if (ret_var != null) { ret_var.sym_info = cfn.return_variable; } } public void check_node_parser_error(SyntaxTree.syntax_tree_node tn) { if (_parser_error == null || tn==null) { return; } if (bad_nodes_in_syntax_tree[tn]!=null) { AddError(new ParserError(_parser_error,_stv.get_location(tn))); } } public type_node select_base_type(type_node_list types, bool only_implicit = false) { type_node ret_type = null; if (types.Count > 0) ret_type = types[0]; for (int i = 1; i single. decimal > всех, но его нельзя присвоить другим { var n1 = type_node_to_int_type(tn1); var n2 = type_node_to_int_type(tn2); if ((int)n1 > (int)n2) { var v = n1; n1 = n2; n2 = v; var t = tn1; tn1 = tn2; tn2 = t; } // Первый тип - меньше или равен if ((int)n1 <= (int)int_types.integer_type && (int)n2 <= (int)int_types.integer_type) return SystemLibrary.SystemLibrary.integer_type; if (n1 == n2) return tn1; // Первый тип - меньше if ((int)n2 == (int)int_types.uint64_type) return SystemLibrary.SystemLibrary.uint64_type; if ((int)n2 == (int)int_types.int64_type) { if ((int)n1 <= (int)int_types.integer_type) return SystemLibrary.SystemLibrary.int64_type; else return SystemLibrary.SystemLibrary.uint64_type; } if ((int)n2 == (int)int_types.uint_type) // longword { if ((int)n1 == 0 || (int)n1 == 2 || (int)n1 == 4) return SystemLibrary.SystemLibrary.int64_type; if ((int)n1 == 1 || (int)n1 == 3) return SystemLibrary.SystemLibrary.uint_type; // longword // n1 = 6 или 7 return SystemLibrary.SystemLibrary.uint64_type; } return null; // это вхолостую } } }