pascalabcnet/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs
Ivan Bondarev ba0b0f8c39 fix #2976
fix #2881
2024-04-01 12:31:21 +02:00

3355 lines
176 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (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<T>(Errors.Error err)
{
syntax_tree_visitor.AddError(err, true);
return default(T);
}
private T AddError<T>(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");
}
}
/// <summary>
/// Этот метод вызывается если мы встречаем простой вызов функии, например f(1).
/// Он определяет является ли эта функция методом класса, вложенной функцией и т.д. и создает соответствующее обращение.
/// Например, для метода класса он добавляет this, а для вложенной функции вычисляет статическую глубину.
/// </summary>
/// <param name="exprs">Список параметров.</param>
/// <param name="si">Список методов.</param>
/// <param name="loc">Расположение вызова.</param>
/// <param name="converted_type">Тип в котором мы находимся. null, если мы вне типа.</param>
/// <param name="top_function">Функция в которой мы находимся.</param>
/// <param name="allow_procedure">Может ли это быть вызов процедуры. false если вызов стоит в выражении или правой части опреатора присваивания.</param>
/// <returns>Возвращает узел вызова метода.</returns>
public expression_node create_full_function_call(expressions_list exprs, List<SymbolInfo> si, location loc,
common_type_node converted_type, common_function_node top_function, bool allow_procedure, List<SyntaxTree.expression> syntax_nodes_parameters = null)
{
function_node fn = select_function(exprs, si, loc, syntax_nodes_parameters);
//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
{
var lambdasInParameters = syntax_nodes_parameters?.Any(ex => ex is SyntaxTree.function_lambda_definition) ?? false;
if (lambdasInParameters)
syntax_tree_visitor.AddError(new SimpleSemanticError(loc, "LAMBDAS_IN_CONSTRUCTOR_PARAMETERS_ARE_FORBIDDEN_IN_THIS_CONTEXT"));
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;
}
/// <summary>
/// Проверяет, что оператор статический метод класса.
/// </summary>
/// <param name="fn">Функция-оператор.</param>
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;
}
}
}
/// <summary>
/// Создает узел преобразования типа, если необходимо.
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
/// <returns>Преобразованное выражение.</returns>
public expression_node convert_type(expression_node en, type_node to)
{
return convert_type(en, to, en.location);
}
/// <summary>
/// Проверяет можно ли неявно преобразовать. Если надо кидает исключение
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
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 bool can_convert_type(type_node from, type_node to)
{
if (from == to)
return true;
possible_type_convertions pct = type_table.get_convertions(from, 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);
}
/// <summary>
/// Создает узел преобразования типа, если необходимо.
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
/// <param name="loc">Явный контекст.</param>
/// <returns>Преобразованное выражение.</returns>
public expression_node convert_type(expression_node en,type_node to, location loc)
{
if (en.type==to)
{
return en;
}
if (to == SystemLibrary.SystemLibrary.system_delegate_type && en is typed_expression)
{
delegated_methods dm = (en as typed_expression).type as delegated_methods;
if (dm.proper_methods.Count > 1)
AddError(loc, "AMBIGUOUS_DELEGATES");
}
if (en.type is compiled_type_node comptn1 && to is compiled_type_node comptn2) // SSM 5/05/20 - Rubantsev csfml - две dll - во второй функция с параметром из первой. Типы разные
{
if (comptn1.compiled_type == comptn2.compiled_type
|| comptn1.compiled_type.AssemblyQualifiedName == comptn2.compiled_type.AssemblyQualifiedName
) // увы - тут типы Type разные и хеш-коды у них разные
return en;
}
//TODO: А если наследование?
possible_type_convertions pct = type_table.get_convertions(en.type,to);
if (pct.second!=null)
{
if (pct.second.to == null && en is typed_expression && !to.IsDelegate)
{
syntax_tree_visitor.try_convert_typed_expression_to_function_call(ref en);
return en;
}
if (en is null_const_node && pct.first.convertion_method is basic_function_node)
{
en.type = to;
return en;
}
else
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 && (to as delegated_methods).empty_param_method.ret_type != null)
{
return convert_type(en, (to as delegated_methods).empty_param_method.ret_type, loc);
}
en.location = loc;
if (en.type is delegated_methods dm && dm.proper_methods[0].parameters.Count == 0 && dm.proper_methods[0].ret_type != null)
{
if (to != SystemLibrary.SystemLibrary.object_type && to.IsDelegate)
AddError(new CanNotConvertTypes(en, dm.proper_methods[0].ret_type, to, loc)); // SSM 18/06/20 #2261
else
return en;
}
else if (en.type is undefined_type && en is base_function_call bfc)
throw new SimpleSemanticError(loc, "RETURN_TYPE_UNDEFINED_{0}", bfc.function.name);
else if (en is enum_const_node && (en as enum_const_node).constant_value != 0)
return new int_const_node((en as enum_const_node).constant_value, loc);
else 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 is base_function_call bfc && bfc.function.name.StartsWith(LambdaHelper.lambdaPrefix))
{
AddError(from.location, "EXPLICIT_CASTS_FOR_LAMBDA_EXPRESSIONS_ARE_FORBIDDEN");
}
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;
}
if (t1 is compiled_type_node comptn1 && t2 is compiled_type_node comptn2) // SSM 5/05/20 - Rubantsev csfml - две dll - во второй функция с параметром из первой. Типы разные
{
var tt = comptn1.compiled_type.Assembly == comptn2.compiled_type.Assembly;
if (comptn1.compiled_type == comptn2.compiled_type
/*|| (comptn1.compiled_type.Assembly == comptn2.compiled_type.Assembly && comptn1.compiled_type.FullName == comptn2.compiled_type.FullName)*/
|| comptn1.compiled_type.AssemblyQualifiedName == comptn2.compiled_type.AssemblyQualifiedName
) // увы - тут типы 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<type_node> types1 = ctn1.original_template.GetParamsList(ctn1);
List<type_node> 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;
}
/// <summary>
/// Возвращает список преобразований типов для вызова метода.
/// </summary>
/// <param name="factparams">Список фактических параметров.</param>
/// <param name="formalparams">Список формальных параметров.</param>
/// <param name="is_alone_method_defined">Для единственного метода у которого типы параметров совпадают, но в качестве var параметра мы передаем константное значение мы можем сгенерировать более подробное сообщение об ошибке.</param>
/// <returns>Список преобразований типов.</returns>
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 ||
(factparams[factparams.Count - 1].type is delegated_methods dm) && (dm.proper_methods[0].ret_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);
syntax_tree_visitor.context.converted_type.fields.RemoveElement(vdn as class_field);
}
else
{
vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc);
syntax_tree_visitor.context.converted_namespace.variables.RemoveElement(vdn as namespace_variable);
}
}
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);
syntax_tree_visitor.context.converted_type.fields.RemoveElement(vdn as class_field);
}
else
{
vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc);
syntax_tree_visitor.context.converted_namespace.variables.RemoveElement(vdn as namespace_variable);
}
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);
/*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<factparams.Count;i++)
{
type_node formal_param_type = null;
if ((for_par_type!=null)&&(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)&&(formalparams[i].parameter_type==SemanticTree.parameter_type.var))
{
bool is_pascal_array_ref = false;
bool is_ok = false;
if (factparams[i].is_addressed==false || factparams[i] is static_compiled_variable_reference scvr && scvr.var.compiled_field.IsInitOnly
|| factparams[i] is compiled_variable_reference cvr && cvr.var.compiled_field.IsInitOnly)
{
if (factparams[i].semantic_node_type == semantic_node_type.common_method_call)
{
common_method_call cmc = (common_method_call)factparams[i];
internal_interface ii = cmc.obj.type.get_internal_interface(internal_interface_kind.bounded_array_interface);
if (ii != null)
{
if (cmc.function_node.name == compiler_string_consts.get_val_pascal_array_name)
{
bounded_array_interface bai = (bounded_array_interface)ii;
class_field cf = bai.int_array;
expression_node left = new class_field_reference(cf, cmc.obj, cmc.location);
expression_node right = cmc.parameters[0];
//right = convert_type(right, SystemLibrary.SystemLibrary.integer_type);
right = convert_type(right, (ii as bounded_array_interface).ordinal_type_interface.elems_type);
right = create_simple_function_call(SystemLibrary.SystemLibrary.int_sub, cmc.location, right,
new int_const_node(bai.ordinal_type_interface.ordinal_type_to_int(bai.ordinal_type_interface.lower_value),cmc.location));
factparams[i] = new simple_array_indexing(left, right, cmc.type, cmc.location);
is_pascal_array_ref = true;
}
}
}
if (!is_pascal_array_ref)
{
//Если мы попали сюда, то мы пытаемся передать по ссылке значение,
//которое не мохет быть передано по ссылке. Например, передать
//по ссылки из одной функции в другую константный параметр.
if (is_alone_method_defined)
{
if (syntax_tree_visitor.assign_is_converting)
{
AddError(factparams[i].location, "CAN_NOT_ASSIGN_TO_LEFT_PART");
}
else
{
if (formalparams[i] is common_parameter && (formalparams[i] as common_parameter).concrete_parameter_type == concrete_parameter_type.cpt_const /*&& factparams[i] is common_parameter_reference*/)
{
is_ok = true;
}
else if (formalparams[i] is common_parameter && (formalparams[i] as common_parameter).concrete_parameter_type == concrete_parameter_type.cpt_const)
;
//throw new ThisExpressionCanNotBePassedAsConstParameter(factparams[i].location);
else if (is_string_getter(factparams[i]))
{
if (factparams[i] is compiled_function_call)
factparams[i] = make_unmanaged_string_getter(factparams[i] as compiled_function_call);
else
factparams[i] = make_unmanaged_shortstring_getter(factparams[i] as base_function_call);
is_ok = true;
}
else
AddError(new ThisExpressionCanNotBePassedAsVarParameter(factparams[i]));
}
}
else if (is_string_getter(factparams[i]))
{
if (factparams[i] is compiled_function_call)
factparams[i] = make_unmanaged_string_getter(factparams[i] as compiled_function_call);
else
factparams[i] = make_unmanaged_shortstring_getter(factparams[i] as base_function_call);
is_ok = true;
}
if (!is_ok)
return null;
}
}
}
//Разобраться: может лучше добавлять null к списку.
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);
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 = 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)&&(formalparams[i].parameter_type==SemanticTree.parameter_type.var))
{
return null;
}
else
{
ptc = type_table.get_convertions(factparams[i].type, formal_param_type);
if (factparams[i] is null_const_node && !type_table.is_with_nil_allowed(formal_param_type) && !formal_param_type.IsPointer) // SSM 01.07.19 - nil не может быть преобразована за счёт вызова функции
{
ptc.first = null;
}
if (ptc.first==null)
{
if (type_table.is_derived(formal_param_type, factparams[i].type))
{
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);
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 = 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
{
//issue #2161 - SSM 12.03.2020
//issue #348
if ((formal_param_type == SystemLibrary.SystemLibrary.object_type || formal_param_type.IsDelegate) && factparams[i].type is delegated_methods)
{
possible_type_convertions ptci = new possible_type_convertions();
ptci.first = null;
ptci.second = null;
if (formal_param_type.instance_params != null && formal_param_type.instance_params.Count > 0)
{
var fn = (factparams[i].type as delegated_methods).proper_methods[0].simple_function_node;
if (fn.is_generic_function)
{
var fn_instance = fn.get_instance(formal_param_type.instance_params, true, factparams[i].location);
delegated_methods dm = new delegated_methods();
if (fn is common_namespace_function_node)
dm.proper_methods.AddElement(new common_namespace_function_call(fn_instance as common_namespace_function_node, factparams[i].location));
factparams[i].type = dm;
}
else if (!is_alone_method_defined)
return null;
}
else if (!is_alone_method_defined && formal_param_type.IsDelegate)
return null;
ptci.from = factparams[i].type;
ptci.to = formal_param_type;
if (formal_param_type.IsDelegate)
{
var ttc = type_table.get_convertions(formal_param_type, factparams[i].type);
if (ttc.first == null)
{
if (is_alone_method_defined) // если мы сюда попали, то ошибка более явная
{
error = new CanNotConvertTypes(factparams[i], factparams[i].type, formal_param_type, locg);
return null;
}
else
return null;
}
}
tc.AddElement(ptci);
factparams[i] = syntax_tree_visitor.CreateDelegateCall((factparams[i].type as delegated_methods).proper_methods[0]);
//return tc;
}
else if (is_alone_method_defined) // если мы сюда попали, то ошибка более явная
{
error = new CanNotConvertTypes(factparams[i], factparams[i].type, formal_param_type, locg);
return null;
}
else
return null;
//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))
{
if (right.from.IsDelegate && right.to.IsDelegate && left.to == SystemLibrary.SystemLibrary.object_type)
return type_conversion_compare.less_type_conversion;//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;
}
public enum MoreSpecific { Left, Right, None}
// SSM 04/07/2021
public MoreSpecific compare_more_specific(function_node left_func, function_node right_func, possible_type_convertions_list left, possible_type_convertions_list right)
{
bool LeftIsMoreSpecific = false;
bool RightIsMoreSpecific = false;
var left_original = left_func.original_function;
var right_original = right_func.original_function;
if (left_original != null && right_original != null)
{
for (var i = 0; i < left_original.parameters.Count; i++)
{
if (left_original.parameters[i].is_params || i < right_original.parameters.Count && right_original.parameters[i].is_params || i >= right_original.parameters.Count)
{
return MoreSpecific.None;
}
var ltt = left_original.parameters[i].type;
var rtt = right_original.parameters[i].type;
if (ltt.is_generic_parameter && !rtt.is_generic_parameter)
{
RightIsMoreSpecific = true;
if (left != null && right != null && left.Count > 0 && right.Count > 0)
{
type_conversion_compare tcc = compare_type_conversions(left[0], right[0]);
if (tcc == type_conversion_compare.greater_type_conversion && right[0].first != null && right[0].first.convertion_method != null && !(right[0].first.convertion_method is basic_function_node))
RightIsMoreSpecific = false;//ignore user defined implicit conversions
}
continue;
}
if (rtt.is_generic_parameter && !ltt.is_generic_parameter)
{
LeftIsMoreSpecific = true;
if (left != null && right != null && left.Count > 0 && right.Count > 0)
{
type_conversion_compare tcc = compare_type_conversions(left[0], right[0]);
if (tcc == type_conversion_compare.less_type_conversion && left[0].first != null && left[0].first.convertion_method != null && !(left[0].first.convertion_method is basic_function_node))
LeftIsMoreSpecific = false;//ignore user defined implicit conversions
}
continue;
}
var lt = ltt as generic_instance_type_node;
var rt = rtt as generic_instance_type_node;
if (lt == null || rt == null)
continue;
if (lt.original_generic == rt.original_generic)
{
var lins = lt.instance_params;
var rins = rt.instance_params;
for (int j = 0; j < rins.Count; j++)
{
if (lins[j].is_generic_parameter && !rins[j].is_generic_parameter)
RightIsMoreSpecific = true;
else if (rins[j].is_generic_parameter && !lins[j].is_generic_parameter)
LeftIsMoreSpecific = true;
}
}
}
}
if (RightIsMoreSpecific && !LeftIsMoreSpecific)
return MoreSpecific.Right;
if (LeftIsMoreSpecific && !RightIsMoreSpecific)
return MoreSpecific.Left;
return MoreSpecific.None;
}
private method_compare compare_methods(function_node left_func, function_node right_func,
possible_type_convertions_list left,possible_type_convertions_list right)
{
// Нет распознавания глубоко вложенных типов на IsMoreSpecific - только на глубину 1 или 2
var moreSpec = compare_more_specific(left_func, right_func, left, right);
if (moreSpec == MoreSpecific.Left)
return method_compare.greater_method;
if (moreSpec == MoreSpecific.Right)
return method_compare.less_method;
// а иначе пока ничего не возвращать
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<left.Count;i++)
{
if (i >= right.Count)
break;
type_conversion_compare tcc=compare_type_conversions(left[i],right[i]);
if (tcc==type_conversion_compare.less_type_conversion)
{
right_greater=true;
}
if (tcc==type_conversion_compare.greater_type_conversion)
{
left_greater=true;
}
if ((left_greater)&&(right_greater))
{
return method_compare.not_comparable_methods;
}
}
if ((left_greater)&&(!right_greater))
{
return method_compare.greater_method;
}
if ((!left_greater)&&(right_greater))
{
return method_compare.less_method;
}
if ((left_greater) && (right_greater))
{
return method_compare.not_comparable_methods;
}
if ((left.snl != null) && (right.snl == null))
{
return method_compare.less_method;
}
if ((left.snl == null) && (right.snl != null))
{
return method_compare.greater_method;
}
if (!left_func.is_generic_function_instance && right_func.is_generic_function_instance) // SSM 29.06.19 Это неверно для Run<int>(Func<int>) против Run(Func<Task>)
{
if (left_func is basic_function_node)
return method_compare.less_method;
else
{
if (left.Count > 0 && right.Count > 0 && left[0].from is delegated_methods && right[0].from is delegated_methods && right[0].to.is_generic_type_instance
&& (left[0].from as delegated_methods).proper_methods[0].ret_type is lambda_any_type_node && (right[0].from as delegated_methods).proper_methods[0].ret_type is lambda_any_type_node)
{
var llist = right_func.get_generic_params_list();
var rlist = right[0].to.instance_params;
if (llist.Count == rlist.Count)
{
for (int i=0; i<llist.Count; i++)
if (llist[i] != rlist[i])
return method_compare.greater_method;
return method_compare.less_method;
}
else
return method_compare.greater_method;
}
else
return method_compare.greater_method;
}
}
if (left_func.is_generic_function_instance && !right_func.is_generic_function_instance)
{
if (right_func is basic_function_node)
return method_compare.greater_method;
else
return method_compare.less_method;
}
if (left_func.is_generic_function_instance && right_func.is_generic_function_instance)
{
if (left_func.generic_parameters_count > 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<left_func.parameters.Count; i++)
if (left_func.parameters[i].type != right_func.parameters[i].type)
{
eq = false;
break;
}
if (eq)
{
// SSM 03/07/2021 - в связи с EachCount с GroupBy и без
/*bool LeftIsMoreSpecific = false;
bool RightIsMoreSpecific = false;
var left_original = left_func.original_function;
var right_original = right_func.original_function;
if (left_original != null && right_original != null)
{
for (var i = 0; i < left_original.parameters.Count; i++)
{
var ltt = left_original.parameters[i].type;
var rtt = right_original.parameters[i].type;
if (ltt.is_generic_parameter && !rtt.is_generic_parameter)
{
RightIsMoreSpecific = true;
continue;
}
if (rtt.is_generic_parameter && !ltt.is_generic_parameter)
{
LeftIsMoreSpecific = true;
continue;
}
var lt = ltt as generic_instance_type_node;
var rt = rtt as generic_instance_type_node;
if (lt == null || rt == null)
continue;
if (lt.original_generic == rt.original_generic)
{
var lins = lt.instance_params;
var rins = rt.instance_params;
for (int j = 0; j < rins.Count; j++)
{
if (lins[j].is_generic_parameter && !rins[j].is_generic_parameter)
RightIsMoreSpecific = true;
else if (rins[j].is_generic_parameter && !lins[j].is_generic_parameter)
LeftIsMoreSpecific = true;
}
}
}
}
if (RightIsMoreSpecific && !LeftIsMoreSpecific)
return method_compare.less_method;
if (LeftIsMoreSpecific && !RightIsMoreSpecific)
return method_compare.greater_method;*/
// end SSM 03/07/2021
// Это не всегда правильно срабатывает
var lc = left_func.get_generic_params_list().Count;
var rc = right_func.get_generic_params_list().Count;
if (lc < rc)
return method_compare.greater_method;
if (lc > rc)
return method_compare.less_method;
// Тут совпадать они не могут, но если совпадают - пусть уж будут несравнимыми
}
}
}
if (left_func.return_value_type != null && right_func.return_value_type != null && function_eq_params(left_func, right_func, true))
{
var tc = type_table.compare_types(left_func.return_value_type, right_func.return_value_type);
if (tc == type_compare.less_type)
return method_compare.greater_method;
if (tc == type_compare.greater_type)
return method_compare.less_method;
}
return method_compare.not_comparable_methods;
}
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)
{
if (tn1.is_generic_parameter && tn2.is_generic_parameter)
return tn1.generic_param_index == tn2.generic_param_index;
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 type_or_base_type_implements_interface(type_node tn, type_node interf)
{
do {
if (tn.ImplementingInterfaces.Contains(interf))
return true;
tn = tn.base_type;
} while (tn != null);
return 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
{
if (left.return_value_type != null && right.return_value_type != null && left.return_value_type.is_generic_parameter && right.return_value_type.is_generic_parameter)
{
//if (string.Compare(left.return_value_type.name, right.return_value_type.name, true) != 0)
// return false;
return eq_type_nodes(left.return_value_type, right.return_value_type, false);
}
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<type_node> left_type_params = left.get_generic_params_list();
List<type_node> 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)
{
if (ptc.first.from is null_type_node || ptc.second.to == null || ptc.second.from is null_type_node || ptc.second.from.is_generic_parameter)
continue; // SSM 9/12/20 fix 2363
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)
{
var needToConvertParamsToFunctionCall = true; // SSM #2079 29/06/20
var lastIsParams = fn.parameters.Count > 0 && fn.parameters[fn.parameters.Count - 1].is_params;
if (lastIsParams && fn.parameters[fn.parameters.Count - 1].type.element_type.IsDelegate)
needToConvertParamsToFunctionCall = false; // параметры params - преобразовывать ли в вызовы
for (int i = 0; i < exprs.Count; i++)
{
// надо отдельно расшифровывать params и в них тоже не преобразовывать если там делегаты
// Если функция возвращает функцию, то это к сожалению не будет работать
if (i <= fn.parameters.Count - 1 && fn.parameters[i].type.IsDelegate || lastIsParams && i >= fn.parameters.Count - 1 && !needToConvertParamsToFunctionCall)
{
// ничего не делать
}
else
{
var ex = exprs[i];
syntax_tree_visitor.try_convert_typed_expression_to_function_call(ref ex);
exprs[i] = ex;
}
} // SSM end 29/06/20
for (int i=0;i<exprs.Count;i++)
{
if ((ptcal.snl != null) && (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);
List<expression_node> args = new List<expression_node>();
for (int j = fn.parameters.Count - 1; j < exprs.Count; j++)
args.Add(convert_type(exprs[j], fn.parameters[fn.parameters.Count - 1].type.element_type));
exprs.remove_range(fn.parameters.Count - 1, exprs.Count - fn.parameters.Count);
//exprs.AddElement(ptcal.var_ref);
//exprs[i] = ptcal.var_ref;
exprs[i] = new array_initializer(args, ptcal.var_ref.location);
exprs[i].type = fn.parameters[fn.parameters.Count - 1].type;
break;
}
if (ptcal.Count <= i)
{
continue;
}
if ((ptcal[i] == null) || (ptcal[i].first == null) || (exprs[i] is null_const_node && exprs[i].conversion_type == null))
{
continue;
}
if (ptcal[i].second != null && ptcal[i].second.to == null)
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;
var arri = new array_initializer(new List<expression_node>(), ptcal.var_ref.location);
arri.type = fn.parameters[fn.parameters.Count - 1].type;
exprs.AddElement(arri);
}
// SSM 02/05/23 - этот код ответственен за добавление параметров по умолчанию.
// После внедрения именованных параметров здесь необходим более интеллектуальный код - для соответствующих
// именованных параметров вместо значений по умолчанию будут добавляться их значения при вызове
// Поступим проще - выберем одну функцию с указанными именованными параметрами и подставим все - по умолчанию и именованные
// Если функций с указанными именоваными параметрами остается две - то кидать ошибку
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) // default_value хранится в формальном параметре. А значение именованного параметра хранится в вызове!!
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);
var arri = new array_initializer(new List<expression_node>(), ptcal.var_ref.location);
arri.type = fn.parameters[fn.parameters.Count - 1].type;
exprs.AddElement(arri);
}
//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, List<function_node> 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, List<function_node> 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, List<function_node> funcs)
{
return find_eq_return_value_method_in_list(fn, funcs);
}
/// <summary>
/// Получение compiled_type_node из либо compiled_type_node либо compiled_generic_instance_type_node. Используется ниже локально
/// </summary>
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;
}
// Эту функцию можно написать оптимальнее - без внешнего while. Например.
// Запускаем алгоритм сортировки на частичном порядке. Ищем min из оставшихся и меняем его местами с текущим.
// Потом проходимся по частично отсортированному и из пары соседних удаляем тот, что меньше
private void delete_greater_functions(List<function_node> set_of_possible_functions, possible_type_convertions_list_list tcll)
{
bool remove = true;
while (remove)
{
remove = false;
// Удаляем из всех возможных перегруженных версий функций те, которые больше какой-то. Та, которая меньше по всем параметрам, остаётся.
// По идее это надо делать для каждой дистанции отдельно - тогда баг #1970 уйдёт
var i = 0;
while (i < set_of_possible_functions.Count - 1)
{
var 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) // f[i]>f[j] - значит, удалять надо f[i], а в коде наоборот!!! Странно...
{
tcll.remove_at(j);
set_of_possible_functions.RemoveAt(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.RemoveAt(j);
remove = true;
}
else
{
j++;
}
}
i++;
}
}
}
private void delete_functions_with_less_result_type(List<function_node> set_of_possible_functions)
{
function_node best_function = null;
List<function_node> to_remove = new List<function_node>();
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);
}
}
public List<function_node> select_function_helper(expressions_list parameters, List<SymbolInfo> functions,
location loc, List<SyntaxTree.expression> syntax_nodes_parameters, bool only_from_not_extensions,
out Errors.Error err_out)
{
// Возвращает список function_node, если он состоит из одной, то меняет parameters,
// в err возвращает ошибку или null если ошибки не было
// Возможная проблема - parameters меняется после первого вызова с ошибкой и во втором вызове он некорректный
err_out = null;
var set_of_possible_functions = new List<function_node>();
if (functions == null)
{
err_out = new NoFunctionWithThisName(loc);
return set_of_possible_functions;
}
string FunctionName = "";
if (functions != null && functions.Count > 0)
FunctionName = (functions[0].sym_info as function_node).name;
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;
bool is_op = compiler_string_consts.GetNETOperName(first_function.name) != null || first_function.name.ToLower() == "in";
basic_function_node _tmp_bfn = functions.FirstOrDefault().sym_info as basic_function_node;
List<function_node> indefinits = new List<function_node>();
foreach (SymbolInfo function in functions)
{
if (function.sym_info is compiled_function_node cfn0 &&
cfn0.comperehensive_type is compiled_type_node ctn0 &&
(ctn0.compiled_type.Name == compiler_string_consts.pascalSystemUnitName + compiler_string_consts.ImplementationSectionNamespaceName || ctn0.compiled_type.Name == compiler_string_consts.pascalExtensionsUnitName + compiler_string_consts.ImplementationSectionNamespaceName)
&& !ctn0.compiled_type.Assembly.FullName.StartsWith("PABCRtl")) // пропустить функции (методы расширения), определенные в сборке в ПИ PABCSystem, но не в PABCRtl.dll
continue;
// В режиме 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 (function.sym_info.general_node_type != general_node_type.function_node && function.sym_info.general_node_type != general_node_type.property_node)
{
continue;
}
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)
{
var fm = find_eq_method_in_list(fn, set_of_possible_functions); // без возвращаемого значения в отличие от is_exist_eq_method_in_list
bool bo = fm != null;
if (bo)
bo = eq_type_nodes(fn.return_value_type, fm.return_value_type);
//var bo = is_exist_eq_method_in_list(fn, set_of_possible_functions) != null;
if (bo)
{
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.Add(fn);
}
continue;
}
if (fm != null && fn is common_method_node cmnfn && fm is common_method_node cmnfm && cmnfn.comperehensive_type != cmnfm.comperehensive_type)
{
//fn = fn;
}
// Если fm и fn принадлежат к разным классам, то не добавлять fn - она принадлежит предку поскольку встречалась позже
else set_of_possible_functions.Add(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;
}
else if ((func = find_eq_method_in_list(fn, set_of_possible_functions)) != null)
{
if (!(fn is compiled_function_node cfn && func is compiled_function_node cfn2 && (cfn.polymorphic_state == polymorphic_state.ps_static || cfn2.polymorphic_state == polymorphic_state.ps_static)))
set_of_possible_functions.Add(fn);
}
else
set_of_possible_functions.Add(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.Add(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.Add(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.Add(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.Add(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.Add(fn);
}
if (set_of_possible_functions.Count == 0 && indefinits.Count == 0)
{
err_out = new NoFunctionWithSameParametresNum(loc, is_alone_method_defined, first_function);
return set_of_possible_functions;
}
//(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
{
// syntax_nodes_parameters в DeduceFunction - ничего плохого нет. Из них фильтруются
// только function_lambda_definition, а в значениях именованных аргументов их не может быть.
// Хотя и в этом случае проблем не вижу
function_node inst = generic_convertions.DeduceFunction(func, parameters,
is_alone_method_defined, syntax_tree_visitor.context, loc, syntax_nodes_parameters);
if (inst == null)
{
try
{
inst = generic_convertions.DeduceFunction(func, parameters, true, syntax_tree_visitor.context, loc, syntax_nodes_parameters);
}
catch
{
}
if (inst == null)
set_of_possible_functions.RemoveAt(i);
else
set_of_possible_functions[i] = inst;
}
else
{
set_of_possible_functions[i] = inst;
}
}
catch (FailedWhileTryingToCompileLambdaBodyWithGivenParametersException exc) //lroman Отлавливаем последнее исключение, которое возникло при попытке скомпилировать тело лямбды с заданными типами параметров
{
set_of_possible_functions.RemoveAt(i);
lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = exc;
}
catch (Errors.Error err1)
{
err_out = err1;
return set_of_possible_functions;
}
}
}
if (lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException != null
&& set_of_possible_functions.Count == 0
&& indefinits.Count == 0)
{
throw lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException.ExceptionOnCompileBody; // Если перебрали все, но ничто не подошло, то кидаем последнее исключение
}
else if (lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException != null
&& set_of_possible_functions.Count > 0
&& indefinits.Count == 0)
{
syntax_tree_visitor.RemoveLastError();
}
if (set_of_possible_functions.Count == 0 && indefinits.Count == 0)
{
if (is_op)
err_out = new OperatorCanNotBeAppliedToThisTypes(first_function.name, parameters[0], parameters.Count > 1 ? parameters[1] : null, loc);
else err_out = new SimpleSemanticError(loc, "CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS", first_function.name);
return set_of_possible_functions;
}
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);
var proc_func_or_lambdaAndNotDelegate_OK_flag = true;
// Цикл по всем параметрам. Если формальный - процедура, а фактический - функция, то tc делать = null и взводить специальный флаг чтобы не возиться с делегатами дальше
if (set_of_possible_functions.Count >= 2 && set_of_possible_functions[i].parameters.Count == parameters.Count)
for (var k = 0; k < parameters.Count; k++)
{
var fact = parameters[k];
var formal = set_of_possible_functions[i].parameters[k];
if (fact.type is delegated_methods dm)
{
var fact_is_function_with_return_value = dm.proper_methods.Count > 0 && dm.proper_methods[0].function.return_value_type != null;
var fact_is_lambda = syntax_nodes_parameters != null && k < syntax_nodes_parameters.Count && syntax_nodes_parameters[k] is SyntaxTree.function_lambda_definition;
var form_is_procedure = false;
var form_is_delegate = false;
//if (formal.type is compiled_type_node || // Это на случай System.Action или ()->()
// formal.type is compiled_type_node) // Это на случай procedure
{
var d = formal.type.internal_interfaces;
if (d != null && d.ContainsKey(internal_interface_kind.delegate_interface))
{
var q = d[internal_interface_kind.delegate_interface] as delegate_internal_interface;
if (q != null)
form_is_delegate = true;
if (q != null && q.return_value_type == null) // Это процедура
form_is_procedure = true;
}
}
if (fact_is_function_with_return_value && form_is_procedure)
{
proc_func_or_lambdaAndNotDelegate_OK_flag = false;
break;
}
if (fact_is_lambda && !form_is_delegate) // лямбда вместо не делегата - исключает функцию из рассмотрения
{
proc_func_or_lambdaAndNotDelegate_OK_flag = false;
break;
}
}
}
if (proc_func_or_lambdaAndNotDelegate_OK_flag == false)
tc = null;
// Вот здесь - если фактический параметр - функция, а формальный - процедура хотя бы в одном параметре, то надо нивелировать все преобразования и присваивать tc=null и не влазить в следующий код!!!
if (err != null)
{
err_out = err;
return set_of_possible_functions;
}
//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)
{
err_out = err;
return set_of_possible_functions;
}
}
}
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.RemoveAt(j);
}
else
{
j++;
}
}
if (set_of_possible_functions.Count == 0 && indefinits.Count == 0)
{
if (_is_assigment && parameters.Count == 2)
err_out = new CanNotConvertTypes(parameters[1], parameters[1].type, parameters[0].type, parameters[1].location);
else if (_tmp_bfn != null && parameters.Count == 2)
err_out = new OperatorCanNotBeAppliedToThisTypes(_tmp_bfn.name, parameters[0], parameters[1], loc);
else if (is_op)
err_out = new OperatorCanNotBeAppliedToThisTypes(first_function.name, parameters[0], parameters.Count > 1 ? parameters[1] : null, loc);
else err_out = new NoFunctionWithSameArguments(FunctionName, loc, is_alone_method_defined);
return set_of_possible_functions;
}
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;
}
// Если остались параметры функция и процедура - обе без параметров, но функция возвращает T, то функция будет удалена этим алгоритмом, что неправильно!
// Потому что не учитывается вызов - в вызове может быть функция!!
delete_greater_functions(set_of_possible_functions, tcll); // SSM 06/06/19 refactoring
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;
}
//Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений
//в дальнейшем может вызвать странное поведение, это надо проверить
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
// добавил это условие из-за комментария. Не понимаю, почему иначе не работает +=. Все тесты проходят 01.07.19 если закомментировать вообще этот if !!!
&& set_of_possible_functions[0].name == "+=" && set_of_possible_functions[1].name == "+=")
{
var tlist = new List<function_node>();
tlist.Add(set_of_possible_functions[0]);
return tlist;
}
if (indefinits.Count > 0)
{
if (indefinits.Count == 1 && set_of_possible_functions.Count == 0)
{
var tlist1 = new List<function_node>();
tlist1.Add(indefinits[0]);
return tlist1;
}
indefinits.AddRange(set_of_possible_functions);
var tlist = new List<function_node>();
tlist.Add(new indefinite_functions_set(indefinits));
return tlist;
}
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);
var tlist = new List<function_node>();
tlist.Add(new indefinite_functions_set(indefinits));
return tlist;
}
// Удалить функции, у которых тип возвращаемого значения меньше.
// Тут это ошибка т.к. параметры могут соответствовать точнее, а они проверяются дальше. Приоритет должен даваться параметрам
//delete_functions_with_less_result_type(set_of_possible_functions);
// Формирование словаря списков функций с одинаковым значением расстояния
// SSM 07/11/17 Для a.Average(x->x) - остаётся 4 функции. На этом уровне выбрать невозможно:
// Average(IEnumerable<integer>,integer->real): real
// Average(IEnumerable<integer>,integer->int64): real
// Average(IEnumerable<integer>,integer->Nullable<integer>): real
// Average(IEnumerable<integer>,integer->integer): real
// Дело в том, что на этом уровне лямбда x->x имеет тип lambda_anytype->lambda_anytype. Все подходят :)
SortedDictionary<int, List<function_node>> distances = new SortedDictionary<int, List<function_node>>();
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;
expression_node en = parameters[i];
syntax_tree_visitor.try_convert_typed_expression_to_function_call(ref en);
type_node from = en.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<function_node> lst;
if (distances.TryGetValue(distance, out lst))
{
lst.Add(fn);
}
else
{
lst = new List<function_node>();
lst.Add(fn);
distances[distance] = lst;
}
}
// Оставшиеся функции отсортированы по расстояниям
foreach (int dist in distances.Keys) // Дистанции упорядочены по возрастанию. Логика тут странная и видимо неправильная:
// если для какой-то минимальной дистанции найдется ровно одна функция, то она и выбирается
// если две и больше - то они пробрасываются и мы переходим к бОльшей дистанции
{
List<function_node> funcs = distances[dist];
// Удалить функции, у которых тип возвращаемого значения меньше.
// Тут это ошибка т.к. параметры могут соответствовать точнее, а они проверяются дальше. Приоритет должен даваться параметрам
// SSM 27.07.19 перенес это сюда чтобы удаление происходило среди функций с одной дистанцией. В строке 2162 закомментировал
delete_functions_with_less_result_type(funcs);
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)
{
err_out = err;
return set_of_possible_functions;
}
convert_function_call_expressions(funcs[0], parameters, tcl); // вот тут заполняются параметры
var tlist = new List<function_node>();
tlist.Add(funcs[0]);
return tlist;
}
Func<Type, bool> IsFunc = t => t.IsGenericType && t.FullName.StartsWith("System.Func");
Func<type_node, Type> get_type = tt =>
{
var ct = get_compiled_type_node(tt);
return ct?.compiled_type;
};
Func<type_node, bool> 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; // если не у всех, то выйти из цикла и вернуть ошибку о многозначности выбора функции
// Далее остался ТОЛЬКО анализ параметров, являющихся функциями Func!
var bools = Enumerable.Range(1, funcs.Count()).Select(x => true).ToList(); // bools - это фильтр оставляемых функций для данной дистанции
// более точно - bools контролирует только возвращаемые значения - параметры контролирует AllOK
var AllOK = true; // Это означает, что все параметры с одним номером если функциональные, то у них - одинаковое количество и типы Generic-параметров
for (var i = 0; i < ParamsCount; i++)
{
// Хочу взять проекцию всех функций на i-тый параметр
var parsi = funcs.Select(f => f.parameters[i].type);
if (parsi.Any(p => !IsFuncT(p))) // Если какой-то параметр не функция у какой-то из функций с данной дистанцией, то пропустим этот параметр!
// Это - странно! Даже если это - Action, то пропускаем! Это - очень слабая логика!
continue;
// ЕСЛИ ВСЕ ПАРАМЕТРЫ _ НЕ ФУНКЦИИ, ТО ВСЕ ПРОПУСТЯТСЯ!!!
var argss = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()).ToArray(); // последовательность массивов параметров Func
var cnts = argss.Select(a => a.Count());
// Теперь у всех функций i-тый параметр - функциональный
// Проверяем, что у всех функций i-тый параметр будет содержать одинаковое число generic-параметров
var fpi = funcs[0].parameters[i];
var cnt = get_type(fpi.type).GetGenericArguments().Count();
// Проверю, что у остальных функций столько же generic параметров
if (cnts.Any(c => c != cnts.First())) // если нет, то - всё - это ошибка - многозначность. Хотя тут уже не должно быть
{
AllOK = false;
break;
}
// Цикл по параметрам Func кроме последнего
// Здесь проверяется более точно - что у всех i-тых параметров не только одинаковое число generic-параметров, но и одинаковые типы
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)
Type fldiResType = null;
if (syntax_nodes_parameters != null)
{
if (funcs[0].is_extension_method)
{
if (i - 1 >= syntax_nodes_parameters.Count)
fldiResType = null;
// syntax_nodes_parameters[i - 1] или [i] - может быть другое количество синтаксических параметров
// при вызове - тогда упадет. Не понимаю, почему этого не происходит
else fldiResType = ((syntax_nodes_parameters[i - 1] as SyntaxTree.function_lambda_definition)?.RealSemTypeOfResult as compiled_type_node)?.compiled_type;
}
else
{
// Здесь возможно будет несинхрон если в syntax_nodes_parameters пропущены какие то параметры по умолчанию
// Или такого быть не может?
if (i >= syntax_nodes_parameters.Count)
fldiResType = null;
else fldiResType = ((syntax_nodes_parameters[i] as SyntaxTree.function_lambda_definition)?.RealSemTypeOfResult as compiled_type_node)?.compiled_type;
}
}
// странно, но всегда кво параметров в syntax_nodes_parameters на 1 меньше. Иначе падает
// Получается, что fldiResType рассчитывается только если фактическими функциональными параметрами выступают лямбда-выражения. Если имена функций - это не сработает. Это - ОШИБКА!
for (int n = 0; n < bools.Count; n++)
{
if (fldiResType == null || !fldiResType.Equals(kres[n]))
bools[n] = false;
}
}
// SSM 04.06.19
if (!AllOK) // Если у какого-то i-того функционального параметра в массиве func с данной дистанцией не все параметры совпадают по типам и количеству (возвращаемое значение не рассматривается пока),
// то непонятно, что делать. Попробую выходить с исключением, что есть 2 версии
break;
//if (AllOK) // Если все функциональные параметры одинаковы по количеству и типам и по возвращаемому значению всех функциональных параметров подходит только одна функция func, то вернуть её
// Здесь AllOK - согласно коду выше
var bc = bools.Count(x => x == true);
if (bc == 1) // урра! нашлась ровно одна функция! мы победили!
{
var ind = bools.IndexOf(true);
var tlist = new List<function_node>();
tlist.Add(funcs[ind]);
return tlist;
}
if (bc == 0) // SSM 04.06.19 - с этим расстоянием не осталось функций - перейти к следующему расстоянию
continue;
/// Проба 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<int>) либо compiled_generic_instance_type_node (List<A>)
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")))
{
var tlist = new List<function_node>();
tlist.Add(f2);
return tlist;
}
}
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")))
{
var tlist = new List<function_node>();
tlist.Add(f1);
return tlist;
}
}
}
/*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;
}
}*/
}
}
List<function_node> to_remove = new List<function_node>();
foreach (function_node fn in funcs)
{
if (fn.is_generic_function_instance)
foreach (parameter p in fn.original_function.parameters)
{
if (p.type.is_generic_parameter)
{
to_remove.Add(fn);
break;
}
}
}
if (set_of_possible_functions.Count - to_remove.Count == 1)
{
foreach (function_node fn in to_remove)
set_of_possible_functions.Remove(fn);
var tlist = new List<function_node>();
tlist.Add(set_of_possible_functions[0]);
return tlist;
}
}
if (set_of_possible_functions.Count == 2 && set_of_possible_functions[0].return_value_type == set_of_possible_functions[1].return_value_type)
{
if (set_of_possible_functions[0].semantic_node_type == semantic_node_type.basic_function_node && set_of_possible_functions[1].semantic_node_type != semantic_node_type.basic_function_node)
{
var tlist = new List<function_node>();
tlist.Add(set_of_possible_functions[1]);
return tlist;
}
else if (set_of_possible_functions[1].semantic_node_type == semantic_node_type.basic_function_node && set_of_possible_functions[0].semantic_node_type != semantic_node_type.basic_function_node)
{
var tlist = new List<function_node>();
tlist.Add(set_of_possible_functions[0]);
return tlist;
}
}
err_out = new SeveralFunctionsCanBeCalled(loc, set_of_possible_functions);
return set_of_possible_functions;
}
//Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов.
public function_node select_function(expressions_list parameters, List<SymbolInfo> functions, location loc,
List<SyntaxTree.expression> syntax_nodes_parameters = null, bool only_from_not_extensions = false, int params_inc = 0)
{
// only_from_not_extensions = false - не вырезается первый параметр (Включая методы расширения)
// only_from_not_extensions = true - вырезается первый параметр (Исключая методы расширения)
string FunctionName = "";
// а вот в func[i].parameters - только если это метод расширения. Для методов не надо !!!
if (functions != null && functions.Count > 0)
{
FunctionName = (functions[0].sym_info as function_node).name;
}
// с какого номера начинаются именованные параметры
var indexOfFirstNamedArgument = -1;
if (syntax_nodes_parameters != null)
indexOfFirstNamedArgument = syntax_nodes_parameters.FindIndex(exp => exp is SyntaxTree.name_assign_expr);
if (indexOfFirstNamedArgument == -1)
{
Errors.Error err_out;
var list = select_function_helper(parameters, functions, loc, syntax_nodes_parameters, only_from_not_extensions, out err_out);
if (err_out != null)
return AddError<function_node>(err_out);
return list[0];
}
else
{
var indexOfFirstNamedArgumentSem = indexOfFirstNamedArgument + params_inc;
// Вначале ищем среди оставшихся параметров именованные
// Создадим список имен ident именованных аргументов.
List<SyntaxTree.ident> NamesInNamedArguments = syntax_nodes_parameters.Skip(indexOfFirstNamedArgument)
.Select(par => (par as SyntaxTree.name_assign_expr).name).ToList();
foreach (var name in NamesInNamedArguments)
{
// Есть ли это имя в оставшихся параметрах
var found = false;
foreach (var ff in functions)
{
var is_ext1 = (ff.sym_info as function_node).is_extension_method;
var names = (ff.sym_info as function_node).parameters.Skip(indexOfFirstNamedArgument + (is_ext1 ? 1 : 0)).Select(par => par.name);
var fo = names.Contains(name.name, StringComparer.OrdinalIgnoreCase);
if (fo)
{
found = true;
break;
}
}
// Если какое то имя не найдено ни в одном элементе list - found = false - кидать ошибку о неизвестном имени
if (!found)
{
// Здесь - две ситуации. Если среди неименованных аргументов нет, то
var foundUnnamed = false;
foreach (var ff in functions)
{
var is_ext1 = (ff.sym_info as function_node).is_extension_method;
var names = (ff.sym_info as function_node).parameters.Take(indexOfFirstNamedArgument + (is_ext1 ? 1 : 0)).Select(par => par.name);
var fo = names.Contains(name.name, StringComparer.OrdinalIgnoreCase);
if (fo)
{
foundUnnamed = true;
break;
}
}
if (!foundUnnamed)
return AddError<function_node>(syntax_tree_visitor.get_location(name), "UNDEFINED_NAMED_ARGUMENT_{0}", name.name);
// иначе: Именованный аргумент Вася задает параметр, который уже получил значение как неименованный аргумент
return AddError<function_node>(syntax_tree_visitor.get_location(name), "NAMED_ARGUMENT_{0}_SPECIFIES_PARAMETER_THAT_HAD_VALUE_AS_UNNAMED_ARGUMENT", name.name);
}
}
// сделаем копию parameters без именованных аргументов
var parameters_helper = new expressions_list();
for (int i = 0; i < indexOfFirstNamedArgumentSem; i++)
parameters_helper.AddElement(parameters[i]);
Errors.Error err_out;
var syntax_nodes_parameters1 = syntax_nodes_parameters.Take(indexOfFirstNamedArgument).ToList();
var list = select_function_helper(parameters_helper, functions, loc, syntax_nodes_parameters1, only_from_not_extensions, out err_out);
if (list.Count == 0 && err_out != null) // С именованными уже точно ничего не получится
return AddError<function_node>(new NoFunctionWithSameArguments(FunctionName, loc, functions.Count == 1));
// Теперь остались функции functions, такие что каждый именованный аргумент есть хотя бы в одной из них
var hs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
for (int i = indexOfFirstNamedArgument; i < syntax_nodes_parameters.Count; i++)
{
var nae = syntax_nodes_parameters[i] as SyntaxTree.name_assign_expr;
hs.Add(nae.name.name);
}
// В syntax_nodes_parameters и parameters по идее должно быть одно и то же количество значений
// В C# - вот такое сообщение об ошибке:
// Наиболее подходящий перегруженный метод 'proc' не имеет параметра с именем 'Вася'
// Удалим из list все неподходящие, где нет таких имен параметров в оставшейся части
list.RemoveAll(ff =>
{
var is_ext1 = ff.is_extension_method;
var names = ff.parameters.Skip(indexOfFirstNamedArgument + (is_ext1 ? 1 : 0)).Select(par => par.name);
var hsnames = new HashSet<string>(names, StringComparer.OrdinalIgnoreCase);
return !hs.IsSubsetOf(hsnames);
// то есть все имена в именованных аргументах должны находиться среди оставшихся параметров по умолчанию
});
if (list.Count == 0)
return AddError<function_node>(new NoFunctionWithSameArguments(FunctionName, loc, true)); // или false - не знаю
if (list.Count > 1)
return AddError<function_node>(new SeveralFunctionsCanBeCalled(loc, list)); // или другое сообщение
// Теперь раз в list осталась одна функция, найти её в functions и только её и оставить
// Надо делать копию functions иначе это влияет на следующий код
if (list[0].is_generic_function_instance)
list[0] = list[0].original_function;
var functions1 = functions.Where(fun => fun.sym_info == list[0]).ToList();
if (functions1.Count == 0)
return AddError<function_node>(new NoFunctionWithSameArguments(FunctionName, loc, true)); // это не должно случиться, но вдруг
// Вот и в functions осталась одна функция
// Теперь делаем словарь сопоставлений именам -> expression_node (в параметрах)
var dict = new Dictionary<string, expression_node>(StringComparer.OrdinalIgnoreCase); // Это словарь именованных аргументов
for (int i = indexOfFirstNamedArgument; i < syntax_nodes_parameters.Count; i++)
{
var nae = syntax_nodes_parameters[i] as SyntaxTree.name_assign_expr;
//dict[nae.name.name] = parameters[i + (NeedIncrementIndexFNA ? 1 : 0)]; // parameters и syntax_nodes_parameters д.б.одной длины
dict[nae.name.name] = parameters[i + params_inc];
}
// Вот теперь как-то хвост в parameters надо менять на параметры по умолчанию или на те, что хранятся в dict
// Я бы очистил хвост parameters и добавлял бы в него как раньше параметры по умолчанию
parameters.remove_range(indexOfFirstNamedArgumentSem, parameters.Count - indexOfFirstNamedArgumentSem); // удалить хвост
var fun1 = functions1[0].sym_info as function_node; // это - единственная функция
var is_ext = fun1.is_extension_method;
for (int i = indexOfFirstNamedArgument + (is_ext ? 1 : 0); i < fun1.parameters.Count; i++) // сверить это с другим кодом
{
var par = fun1.parameters[i];
var paramexpr = par.default_value;
var name = par.name;
if (dict.ContainsKey(name))
paramexpr = dict[name]; // вместо значения по умолчанию взять значение именованного параметра
parameters.AddElement(paramexpr);
}
// И наконец всё готово!!!
// syntax_nodes_parameters мне кажется всё испортят - там именованные аргументы стоят не на своих местах!!!
// Это единственный - опасный и потенциально с ошибками вызов!
// Но ощущение, что всё верно, т.к. это нужно только для параметров лямбд, а у именованных аргументов их быть не может
list = select_function_helper(parameters, functions1, loc, syntax_nodes_parameters, only_from_not_extensions, out err_out);
if (err_out != null)
return AddError<function_node>(err_out);
return list[0];
}
// для именованных параметров последовательность может быть такая
// Если именованных параметров при вызове нет, то - этот алгоритм. Если есть, то
// 1. Оставить только неименованные параметры и вызвать select_function_helper
// Если не найдено ни одной функции, то ошибка и выход
// Если найдена одна функция и это ошибка, то её и кинуть - выход
// Если найдена одна функция и ошибки нет или найдено две и более функций (с ошибкой разумеется), то
// 2. Ищем среди найденных функций только те, в которых среди оставшихся после основных параметрах по умолчанию
// есть параметры по умолчанию ровно с такими же именами как и именованные параметры при вызове
// Повторяющиеся именованные параметры при вызове отсекать ранее
// 3. Думаю, так: если не осталось ни одной функции, то - ошибка
// Если осталось более одной функции, то - ошибка.
// Если осталась ровно одна функция, то
// 4. Сформировать вызов такой функции с полными семантическими параметрами. Вместо параметров по умолчанию
// подставить их значнеия, именованных параметров подставить ИХ значения.
// И вызвать select_function_helper. И либо он вернет ошибку либо единственную правильную функцию
// Основная проблема: parameters - это параметры при вызове, в них нет имён, это семантика
// Взять недостающие значения по умолчанию из functions[0] и заменить именованные их значениями
// В parameters как-то по особому хранить именованные и первый раз не учитывать
}
private int get_type_distance(type_node from, type_node to)
{
if (from == to)
return 0;
if (from is short_string_type_node && to is compiled_type_node ctn && ctn.compiled_type == typeof(System.String))
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, List<function_node> 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<types.Count; i++)
{
if (types[i] == ret_type) continue;
type_compare tc = type_table.compare_types_in_specific_order(types[i], ret_type, only_implicit);
if (tc == type_compare.greater_type && ret_type != SystemLibrary.SystemLibrary.object_type)
ret_type = types[i];
else if (tc == type_compare.non_comparable_type)
{
ret_type = SystemLibrary.SystemLibrary.object_type;
//ret_type = null;
}
}
return ret_type;
}
public type_node select_base_type_for_arr_const_new(type_node_list types, List<expression_node> lst, bool only_implicit = false)
{
type_node ret_type = null;
if (types.Count > 0) ret_type = types[0];
for (int i = 1; i < types.Count; i++)
{
if (types[i] == ret_type) continue;
type_compare tc = type_table.compare_types_in_specific_order(types[i], ret_type, only_implicit);
if (tc == type_compare.greater_type && ret_type != SystemLibrary.SystemLibrary.object_type)
ret_type = types[i];
else if (tc == type_compare.non_comparable_type)
{
AddError(lst[i].location, "UNCOMPARABLE_TYPES_IN_ARRAY_CONST");
}
}
return ret_type;
}
public enum int_types { sbyte_type = 0, byte_type = 1, short_type = 2, ushort_type = 3, integer_type = 4, uint_type = 5, int64_type = 6, uint64_type = 7};
public static bool is_value_int_type(type_node tn)
{
return
tn == SystemLibrary.SystemLibrary.sbyte_type ||
tn == SystemLibrary.SystemLibrary.byte_type ||
tn == SystemLibrary.SystemLibrary.short_type ||
tn == SystemLibrary.SystemLibrary.ushort_type ||
tn == SystemLibrary.SystemLibrary.integer_type ||
tn == SystemLibrary.SystemLibrary.uint_type ||
tn == SystemLibrary.SystemLibrary.int64_type ||
tn == SystemLibrary.SystemLibrary.uint64_type
;
}
public static bool is_value_real_type(type_node tn)
{
return tn == SystemLibrary.SystemLibrary.double_type ||
tn == SystemLibrary.SystemLibrary.float_type
;
}
public static bool is_value_num_type(type_node tn)
{
return is_value_int_type(tn) || is_value_real_type(tn);
}
public type_node int_type_to_type_node(int_types it)
{
switch (it)
{
case int_types.sbyte_type: return SystemLibrary.SystemLibrary.sbyte_type;
case int_types.byte_type: return SystemLibrary.SystemLibrary.byte_type;
case int_types.short_type: return SystemLibrary.SystemLibrary.short_type;
case int_types.ushort_type: return SystemLibrary.SystemLibrary.ushort_type;
case int_types.integer_type: return SystemLibrary.SystemLibrary.integer_type;
case int_types.uint_type: return SystemLibrary.SystemLibrary.uint_type;
case int_types.int64_type: return SystemLibrary.SystemLibrary.int64_type;
case int_types.uint64_type: return SystemLibrary.SystemLibrary.uint64_type;
}
return null; // это вхолостую
}
public int_types type_node_to_int_type(type_node tn)
{
if (tn == SystemLibrary.SystemLibrary.sbyte_type) // shortint
return int_types.sbyte_type;
else if (tn == SystemLibrary.SystemLibrary.byte_type)
return int_types.byte_type;
else if (tn == SystemLibrary.SystemLibrary.short_type) // smallint
return int_types.short_type;
else if (tn == SystemLibrary.SystemLibrary.ushort_type) // word
return int_types.ushort_type;
else if (tn == SystemLibrary.SystemLibrary.integer_type)
return int_types.integer_type;
else if (tn == SystemLibrary.SystemLibrary.uint_type) // longword
return int_types.uint_type;
else if (tn == SystemLibrary.SystemLibrary.int64_type)
return int_types.int64_type;
else if (tn == SystemLibrary.SystemLibrary.uint64_type)
return int_types.uint64_type;
return int_types.uint64_type; // это вхолостую
}
public type_node least_upper_bound_value_int_type(type_node tn1, type_node tn2) // для вещественных: real > 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 (n1 == n2) return tn1;
// Первый тип - меньше или равен
if ((int)n1 <= (int)int_types.integer_type && (int)n2 <= (int)int_types.integer_type) return SystemLibrary.SystemLibrary.integer_type;
// Первый тип - меньше
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; // это вхолостую
}
}
}