2015-06-01 22:15:17 +03:00
// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
//Некоторые алгоритмы . В основном выбор перегруженного метода. Сильно связан с syntax_tree_visitor.
2015-05-14 22:35:07 +03:00
using System ;
using System.Collections.Generic ;
2016-07-22 13:00:58 +03:00
using System.Linq ;
2015-05-14 22:35:07 +03:00
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 ) ;
}
2015-10-13 23:00:29 +03:00
private T AddError < T > ( Errors . Error err )
{
2015-10-18 14:35:44 +03:00
syntax_tree_visitor . AddError ( err , true ) ;
2015-10-13 23:00:29 +03:00
return default ( T ) ;
}
2016-04-14 21:16:31 +03:00
private T AddError < T > ( location loc , string ErrString , params string [ ] values )
{
syntax_tree_visitor . AddError ( loc , ErrString , values ) ;
return default ( T ) ;
}
2015-05-14 22:35:07 +03:00
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 ( ) ;
}
2017-05-25 12:44:01 +03:00
internal statements_list statement_list_stack_first ( )
{
return statement_list_stack . first ( ) ;
}
2015-05-14 22:35:07 +03:00
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 ;
}
2015-10-24 05:32:03 +03:00
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 ) ;
2015-05-14 22:35:07 +03:00
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 :
2015-08-18 13:15:22 +03:00
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 ) ;
2015-05-14 22:35:07 +03:00
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 ) ;
}
2015-12-14 00:17:34 +03:00
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" ) ;
}
}
2015-05-14 22:35:07 +03:00
/// <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>
2018-04-14 18:18:42 +03:00
public expression_node create_full_function_call ( expressions_list exprs , List < SymbolInfo > si , location loc ,
2016-01-21 21:28:36 +03:00
common_type_node converted_type , common_function_node top_function , bool allow_procedure )
{
function_node fn = select_function ( exprs , si , loc ) ;
2015-05-14 22:35:07 +03:00
//allow_procedure = true;
2016-01-21 21:28:36 +03:00
if ( ( ! allow_procedure ) & & ( fn . return_value_type = = null ) )
{
2015-05-14 22:35:07 +03:00
throw new SimpleSemanticError ( loc , "FUNCTION_EXPECTED_PROCEDURE_{0}_MEET" , fn . name ) ;
2016-01-21 21:28:36 +03:00
}
2015-05-14 22:35:07 +03:00
2017-12-29 20:35:00 +03:00
if ( fn . return_value_type is undefined_type )
throw new SimpleSemanticError ( loc , "RETURN_TYPE_UNDEFINED_{0}" , fn . name ) ;
2016-01-21 21:28:36 +03:00
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 :
2015-05-14 22:35:07 +03:00
{
2016-01-21 21:28:36 +03:00
//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 ;
2017-05-25 12:44:01 +03:00
if ( ! syntax_tree_visitor . context . allow_inherited_ctor_call & & ! syntax_tree_visitor . context . can_call_inherited_ctor_call ( statement_list_stack_first ( ) ) )
2016-01-21 21:28:36 +03:00
{
2016-07-10 20:34:51 +03:00
if ( syntax_tree_visitor . inherited_ident_processing )
syntax_tree_visitor . AddError ( new SimpleSemanticError ( loc , "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST" ) ) ;
else
syntax_tree_visitor . AddError ( new SimpleSemanticError ( loc , "CAN_NOT_CALL_CONSTRUCTOR_AS_PROCEDURE" ) ) ;
2016-01-21 21:28:36 +03:00
}
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 ;
2015-05-14 22:35:07 +03:00
}
2016-01-21 21:28:36 +03:00
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 ;
}
2015-05-14 22:35:07 +03:00
//ssyy добавил
case semantic_node_type . compiled_constructor_node :
{
2016-01-21 21:28:36 +03:00
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 ;
2017-05-25 12:44:01 +03:00
if ( ! syntax_tree_visitor . context . allow_inherited_ctor_call & & ! syntax_tree_visitor . context . can_call_inherited_ctor_call ( statement_list_stack_first ( ) ) )
2016-01-21 21:28:36 +03:00
{
throw new SimpleSemanticError ( loc , "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST" ) ;
}
expr_node = ccc ;
break ;
2015-05-14 22:35:07 +03:00
}
2016-01-21 21:28:36 +03:00
case semantic_node_type . indefinite_definition_node :
2015-05-14 22:35:07 +03:00
{
2016-01-21 21:28:36 +03:00
indefinite_function_call ifc = new indefinite_function_call ( fn , loc ) ;
ifc . parameters . AddRange ( exprs ) ;
expr_node = ifc ;
break ;
2015-05-14 22:35:07 +03:00
}
//\ssyy
2016-01-21 21:28:36 +03:00
default :
{
throw new NotSupportedError ( loc ) ;
}
}
return expr_node ;
}
2015-05-14 22:35:07 +03:00
/// <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 ) ;
}
2016-04-14 21:16:31 +03:00
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 ;
}
2015-05-14 22:35:07 +03:00
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 ) ;
2017-07-09 00:36:46 +03:00
if ( pct . first = = null /*&& !type_table.is_derived(from, to)*/ )
2015-05-14 22:35:07 +03:00
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 ;
}
//TODO: А если наследование?
possible_type_convertions pct = type_table . get_convertions ( en . type , to ) ;
if ( pct . second ! = null )
{
2016-07-22 19:17:10 +03:00
AddError ( new TwoTypeConversionsPossible ( en , pct . first , pct . second ) ) ;
2015-05-14 22:35:07 +03:00
}
if ( pct . first = = null )
{
2016-07-22 19:17:10 +03:00
if ( to is delegated_methods & & ( to as delegated_methods ) . empty_param_method ! = null )
{
return convert_type ( en , ( to as delegated_methods ) . empty_param_method . ret_type , loc ) ;
}
2015-05-14 22:35:07 +03:00
en . location = loc ;
2016-07-22 19:17:10 +03:00
AddError ( new CanNotConvertTypes ( en , en . type , to , loc ) ) ;
2015-05-14 22:35:07 +03:00
}
#if ( DEBUG )
check_operator ( pct . first . convertion_method ) ;
#endif
2017-07-02 13:18:56 +03:00
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 ;
2015-05-14 22:35:07 +03:00
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 ;
2016-07-22 19:17:10 +03:00
bfn = new basic_function_node ( SemanticTree . basic_function_type . none , to_type , false ) ;
2015-05-14 22:35:07 +03:00
bfn . parameters . AddElement ( new basic_parameter ( "expr" , from_type , SemanticTree . parameter_type . value , bfn ) ) ;
if ( with_compile_time_executor )
bfn . compile_time_executor = SystemLibrary . SystemLibrary . delegated_empty_method ;
return bfn ;
}
public expression_node explicit_convert_type ( expression_node from , type_node to )
{
if ( from . type = = to )
{
return from ;
}
possible_type_convertions ptc = type_table . get_convertions ( from . type , to , false ) ;
if ( ptc . second ! = null )
{
AddError ( new TwoTypeConversionsPossible ( from , ptc . first , ptc . second ) ) ;
}
if ( ptc . first ! = null )
{
2017-07-02 13:18:56 +03:00
type_node conv_type = from . type ;
2015-05-14 22:35:07 +03:00
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 ;
2018-08-19 20:29:35 +03:00
if ( ptc . first . convertion_method is basic_function_node )
ret . conversion_type = conv_type ;
2015-05-14 22:35:07 +03:00
return ret ;
}
2018-05-08 20:54:14 +03:00
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 ) )
2015-05-14 22:35:07 +03:00
{
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 ) ;
}
2017-07-02 13:18:56 +03:00
type_node conv_type = from . type ;
2015-05-14 22:35:07 +03:00
expression_node expr = create_simple_function_call ( SystemLibrary . SystemLibrary . obj_to_obj , from . location , from ) ;
//TODO: Переделать.
( ( base_function_call ) expr ) . ret_type = to ;
2017-07-02 13:18:56 +03:00
( ( base_function_call ) expr ) . conversion_type = conv_type ;
2015-05-14 22:35:07 +03:00
( ( 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 . 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 ,
2016-05-16 21:45:03 +03:00
parameter_list formalparams , bool is_alone_method_defined , location locg , out Errors . Error error )
2015-05-14 22:35:07 +03:00
{
//TODO:Явно указывать capacity при создании.
possible_type_convertions_list tc = new possible_type_convertions_list ( ) ;
2016-05-16 21:45:03 +03:00
error = null ;
2015-05-14 22:35:07 +03:00
possible_type_convertions ptc ;
if ( factparams . Count > formalparams . Count )
{
if ( ( formalparams . Count = = 0 ) | | ( ! ( formalparams [ formalparams . Count - 1 ] . is_params ) ) )
{
return null ;
}
}
type_node for_par_type = null ;
array_internal_interface aii = null ;
if ( formalparams . Count > 0 )
{
parameter pr = formalparams [ formalparams . Count - 1 ] ;
if ( pr . is_params & &
//это для возможности вызова сразу с массивом[], типа просто не обращаем внимаение на params
! ( factparams . Count = = formalparams . Count & & factparams [ factparams . Count - 1 ] . type = = formalparams [ formalparams . Count - 1 ] . type ) )
{
//TODO: Добавить проверку на правильность.
aii = ( array_internal_interface )
pr . type . get_internal_interface ( internal_interface_kind . unsized_array_interface ) ;
for_par_type = aii . element_type ;
tc . snl = new statement_node_list ( ) ;
location loc = null ;
if ( factparams . Count > 0 ) loc = factparams [ factparams . Count - 1 ] . location ;
//var_definition_node vdn=syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(),loc);
var_definition_node vdn = null ;
if ( syntax_tree_visitor . context . converted_func_stack . size > 0 )
{
common_function_node cfn = syntax_tree_visitor . context . converted_func_stack . first ( ) ;
2016-09-20 20:13:47 +03:00
if ( cfn . is_generic_function | | ! syntax_tree_visitor . context . has_nested_functions & & syntax_tree_visitor . context . converted_func_stack . size = = 1 )
2015-05-14 22:35:07 +03:00
{
vdn = syntax_tree_visitor . context . add_var_definition ( get_temp_arr_name ( ) , loc ) ;
}
2015-10-24 21:18:49 +03:00
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 ) ;
2015-05-14 22:35:07 +03:00
else
vdn = syntax_tree_visitor . context . add_var_definition_in_entry_scope ( get_temp_arr_name ( ) , loc ) ;
}
else if ( syntax_tree_visitor . context . converted_type ! = null )
vdn = syntax_tree_visitor . context . add_field ( get_temp_arr_name ( ) , loc , pr . type , polymorphic_state . ps_static ) ;
else
vdn = syntax_tree_visitor . context . add_var_definition_in_entry_scope ( get_temp_arr_name ( ) , loc ) ;
syntax_tree_visitor . context . close_var_definition_list ( pr . type , null ) ;
expression_node fst = null ;
/ * switch ( syntax_tree_visitor . context . converting_block ( ) )
{
case block_type . function_block :
{
fst = new local_variable_reference ( ( local_variable ) vdn , 0 , loc ) ;
break ;
}
case block_type . namespace_block :
{
fst = new namespace_variable_reference ( ( namespace_variable ) vdn , loc ) ;
break ;
}
} * /
switch ( vdn . semantic_node_type )
{
case semantic_node_type . local_variable :
{
fst = new local_variable_reference ( ( local_variable ) vdn , 0 , loc ) ;
break ;
}
case semantic_node_type . namespace_variable :
{
fst = new namespace_variable_reference ( ( namespace_variable ) vdn , loc ) ;
break ;
}
case semantic_node_type . local_block_variable :
{
fst = new local_block_variable_reference ( ( local_block_variable ) vdn , loc ) ;
break ;
}
case semantic_node_type . class_field :
{
class_field cf = vdn as class_field ;
cf . polymorphic_state = polymorphic_state . ps_static ;
fst = new static_class_field_reference ( cf , loc ) ;
break ;
}
default :
throw new CompilerInternalError ( "Invalid node type" ) ;
}
tc . var_ref = fst ;
int del = factparams . Count - formalparams . Count + 1 ;
int_const_node icn = new int_const_node ( del , loc ) ;
expression_node bfc = create_simple_function_call ( SystemLibrary . SystemLibrary . resize_func ,
loc , fst , icn ) ;
tc . snl . AddElement ( bfc ) ;
/ * if ( factparams . Count = = 0 )
{
possible_type_convertions ptci = new possible_type_convertions ( ) ;
ptci . first = null ;
ptci . second = null ;
ptci . from = null ;
ptci . to = for_par_type ;
tc . AddElement ( ptci ) ;
} * /
}
}
for ( int i = 0 ; i < 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 )
{
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 ( 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
{
if ( is_alone_method_defined )
{
2017-02-19 14:27:51 +03:00
//issue #348
if ( formal_param_type = = SystemLibrary . SystemLibrary . object_type & & factparams [ i ] . type is delegated_methods )
{
possible_type_convertions ptci = new possible_type_convertions ( ) ;
ptci . first = null ;
ptci . second = null ;
ptci . from = factparams [ i ] . type ;
ptci . to = formal_param_type ;
tc . AddElement ( ptci ) ;
factparams [ i ] = syntax_tree_visitor . CreateDelegateCall ( ( factparams [ i ] . type as delegated_methods ) . proper_methods [ 0 ] ) ;
return tc ;
}
else
error = new CanNotConvertTypes ( factparams [ i ] , factparams [ i ] . type , formal_param_type , locg ) ;
2015-05-14 22:35:07 +03:00
}
return null ;
}
}
else
{
tc . AddElement ( ptc ) ;
if ( ( for_par_type ! = null ) & & ( i > = formalparams . Count - 1 ) )
{
expression_node to = new simple_array_indexing ( tc . var_ref , //factparams[formalparams.Count - 1],
new int_const_node ( i - formalparams . Count + 1 , factparams [ i ] . location ) , aii . element_type , factparams [ i ] . location ) ;
expression_node from = create_simple_function_call ( ptc . first . convertion_method ,
factparams [ i ] . location , factparams [ i ] ) ;
statement_node stat = syntax_tree_visitor . find_operator ( compiler_string_consts . assign_name , to , from , factparams [ i ] . location ) ;
tc . snl . AddElement ( stat ) ;
}
}
}
}
if ( tc . snl ! = null )
foreach ( statement_node sn in tc . snl )
sn . location = null ;
return tc ;
}
private simple_array_indexing make_unmanaged_string_getter ( compiled_function_call cfc )
{
return new simple_array_indexing ( cfc . obj , cfc . parameters [ 0 ] , SystemLibrary . SystemLibrary . char_type , cfc . location ) ;
}
private simple_array_indexing make_unmanaged_shortstring_getter ( base_function_call cfc )
{
return new simple_array_indexing ( cfc . parameters [ 0 ] , cfc . parameters [ 1 ] , SystemLibrary . SystemLibrary . char_type , cfc . location ) ;
}
private bool is_string_getter ( expression_node en )
{
if ( en is common_namespace_function_call & & ( en as common_namespace_function_call ) . function_node = = SystemLibrary . SystemLibInitializer . GetCharInShortStringProcedure . sym_info )
{
return true ;
}
else if ( en is compiled_static_method_call & & ( en as compiled_static_method_call ) . function_node = = SystemLibrary . SystemLibInitializer . GetCharInShortStringProcedure . sym_info )
{
return true ;
}
else if ( en is compiled_function_call )
{
if ( ( en as compiled_function_call ) . function_node . cont_type ! = SystemLibrary . SystemLibrary . string_type )
return false ;
if ( ( en as compiled_function_call ) . function_node . name . StartsWith ( "get_" ) )
return true ;
}
return false ;
}
private enum method_compare { less_method , greater_method , not_comparable_methods } ;
private enum type_conversion_compare { less_type_conversion , greater_type_conversion , equal_type_conversions } ;
private type_conversion_compare compare_type_conversions ( possible_type_convertions left , possible_type_convertions right )
{
if ( ( left . first = = null ) & & ( right . first ! = null ) )
{
return type_conversion_compare . greater_type_conversion ;
}
if ( ( left . first ! = null ) & & ( right . first = = null ) )
{
return type_conversion_compare . less_type_conversion ;
}
if ( ( left . first ! = null ) & & ( right . first ! = null ) )
{
convert_types_function_node cleft = left . first . convertion_method as convert_types_function_node ;
convert_types_function_node cright = right . first . convertion_method as convert_types_function_node ;
if ( ( cleft ! = null ) & & ( cright ! = null ) )
{
if ( ( cleft . Good ) & & ( ! cright . Good ) )
{
return type_conversion_compare . greater_type_conversion ;
}
if ( ( ! cleft . Good ) & & ( cright . Good ) )
{
return type_conversion_compare . less_type_conversion ;
}
}
}
/ * if ( ( left . first = = null ) & & ( right . first = = null ) )
{
return type_conversion_compare . equal_type_conversions ;
} * /
//type_compare tc=type_table.compare_types(left.first.to,right.first.to);
type_compare tc = type_table . compare_types ( left . to , right . to ) ;
if ( tc = = type_compare . greater_type )
{
if ( left . to . type_special_kind = = type_special_kind . diap_type & & left . to is common_type_node & & right . to . type_special_kind = = type_special_kind . diap_type & & right . to is common_type_node )
{
tc = type_table . compare_types ( left . to . base_type , right . to . base_type ) ;
if ( tc = = type_compare . greater_type )
return type_conversion_compare . less_type_conversion ;
}
else
return type_conversion_compare . less_type_conversion ;
//return type_conversion_compare.greater_type_conversion;
}
if ( tc = = type_compare . less_type )
{
if ( left . to . type_special_kind = = type_special_kind . diap_type & & left . to is common_type_node & & right . to . type_special_kind = = type_special_kind . diap_type & & right . to is common_type_node )
{
tc = type_table . compare_types ( left . to . base_type , right . to . base_type ) ;
if ( tc = = type_compare . less_type )
return type_conversion_compare . greater_type_conversion ;
}
else
return type_conversion_compare . greater_type_conversion ;
//return type_conversion_compare.less_type_conversion;
}
internal_interface left_del = left . to . get_internal_interface ( internal_interface_kind . delegate_interface ) ;
internal_interface right_del = right . to . get_internal_interface ( internal_interface_kind . delegate_interface ) ;
if ( ( left_del = = null ) & & ( right_del = = null ) )
{
return type_conversion_compare . equal_type_conversions ;
}
if ( ( left_del = = null ) & & ( right_del ! = null ) )
{
return type_conversion_compare . less_type_conversion ;
}
if ( ( left_del ! = null ) & & ( right_del = = null ) )
{
return type_conversion_compare . greater_type_conversion ;
}
return type_conversion_compare . equal_type_conversions ;
}
private method_compare compare_methods ( function_node left_func , function_node right_func ,
possible_type_convertions_list left , possible_type_convertions_list right )
{
function_compare fc = function_node . compare_functions ( left_func , right_func ) ;
if ( fc = = function_compare . less )
{
return method_compare . less_method ;
}
if ( fc = = function_compare . greater )
{
return method_compare . greater_method ;
}
bool left_greater = false ;
bool right_greater = false ;
for ( int i = 0 ; i < left . Count ; i + + )
{
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 )
{
2016-12-03 20:40:39 +03:00
if ( left_func is basic_function_node )
return method_compare . less_method ;
else
return method_compare . greater_method ;
2015-05-14 22:35:07 +03:00
}
if ( left_func . is_generic_function_instance & & ! right_func . is_generic_function_instance )
{
2016-12-03 20:40:39 +03:00
if ( right_func is basic_function_node )
return method_compare . greater_method ;
else
return method_compare . less_method ;
2015-05-14 22:35:07 +03:00
}
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 ;
2015-08-09 16:25:11 +03:00
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 )
{
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 ;
// Тут совпадать они не могут, но если совпадают - пусть уж будут несравнимыми
}
}
2015-05-14 22:35:07 +03:00
}
return method_compare . not_comparable_methods ;
}
//DS добавил этот метод
//А так ли это надо делать?
//Сергей, может ты знаеш?
internal static bool eq_type_nodes ( type_node tn1 , type_node tn2 , bool strong )
{
if ( tn1 = = tn2 )
return true ;
if ( tn1 = = null | | tn2 = = null )
{
return false ;
}
if ( tn1 is lambda_any_type_node | | tn2 is lambda_any_type_node ) //lroman// Считаем, что тип lambda_any_type_node равен всем типам. Это используется при выводе параметров лямбды
return true ;
if ( tn1 . generic_function_container ! = null & & tn2 . generic_function_container ! = null )
{
if ( strong & & tn1 . generic_function_container ! = tn2 . generic_function_container )
{
return false ;
}
return ( tn1 . generic_param_index = = tn2 . generic_param_index ) ;
}
if ( tn1 . type_special_kind ! = tn2 . type_special_kind )
{
return false ;
}
switch ( tn1 . type_special_kind )
{
case type_special_kind . array_kind :
case type_special_kind . set_type :
case type_special_kind . typed_file :
if ( tn1 . type_special_kind = = type_special_kind . array_kind )
{
if ( tn1 is compiled_type_node & & tn2 is compiled_type_node & & ( tn1 as compiled_type_node ) . rank ! = ( tn2 as compiled_type_node ) . rank )
return false ;
if ( tn1 is common_type_node & & tn2 is common_type_node & & ( tn1 as common_type_node ) . rank ! = ( tn2 as common_type_node ) . rank )
return false ;
}
return eq_type_nodes ( tn1 . element_type , tn2 . element_type , strong ) ;
}
ref_type_node rtn1 = tn1 as ref_type_node ;
if ( rtn1 ! = null )
{
ref_type_node rtn2 = tn2 as ref_type_node ;
if ( rtn2 = = null )
{
return false ;
}
return eq_type_nodes ( rtn1 . pointed_type , rtn2 . pointed_type , strong ) ;
}
if ( tn1 . is_generic_type_definition & & tn2 . is_generic_type_instance | |
tn2 . is_generic_type_definition & & tn1 . is_generic_type_instance )
{
type_node tdef , tinst ;
if ( tn1 . is_generic_type_definition )
{
tdef = tn1 ;
tinst = tn2 ;
}
else
{
tdef = tn2 ;
tinst = tn1 ;
}
if ( tinst . original_generic ! = tdef )
{
return false ;
}
2016-02-06 21:06:39 +03:00
if ( tdef is common_type_node )
2015-05-14 22:35:07 +03:00
{
2016-02-06 21:06:39 +03:00
common_type_node ctdef = tdef as common_type_node ;
int count = ctdef . generic_params . Count ;
for ( int i = 0 ; i < count ; + + i )
2015-05-14 22:35:07 +03:00
{
2016-02-06 21:06:39 +03:00
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 ;
}
2015-05-14 22:35:07 +03:00
}
}
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 )
{
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 ) ;
}
//Этот метод сверяет не только параметры, но и возвращаемое значение
2016-03-13 20:50:38 +03:00
public static bool function_eq_params_and_result ( function_node left , function_node right , bool weak = false )
2015-05-14 22:35:07 +03:00
{
2016-03-13 20:50:38 +03:00
if ( ! function_eq_params ( left , right , weak ) )
2015-05-14 22:35:07 +03:00
{
return false ;
}
else
{
return eq_type_nodes ( left . return_value_type , right . return_value_type ) ;
}
}
//Сравниваем типы-параметры generic-функций
public static bool function_eq_generic_params ( function_node left , function_node right )
{
2016-03-13 20:50:38 +03:00
List < type_node > left_type_params = left . get_generic_params_list ( ) ;
List < type_node > right_type_params = right . get_generic_params_list ( ) ;
2015-05-14 22:35:07 +03:00
if ( left_type_params = = null & & right_type_params = = null )
{
return true ;
}
if ( left_type_params = = null | | right_type_params = = null )
{
return false ;
}
if ( left_type_params . Count ! = right_type_params . Count )
{
return false ;
}
for ( int i = 0 ; i < left_type_params . Count ; i + + )
{
if ( string . Compare ( left_type_params [ i ] . name , right_type_params [ i ] . name , true ) ! = 0 )
{
return false ;
}
}
return true ;
}
public static bool function_eq_params ( function_node left , function_node right )
{
return function_eq_params ( left , right , true ) ;
}
public static bool function_eq_params ( function_node left , function_node right , bool compare_parameter_types )
{
if ( compare_parameter_types )
{
if ( ! function_eq_generic_params ( left , right ) )
{
return false ;
}
}
else
{
if ( left . generic_parameters_count ! = right . generic_parameters_count )
{
return false ;
}
}
if ( left . parameters . Count ! = right . parameters . Count )
{
return false ;
}
for ( int i = 0 ; i < left . parameters . Count ; i + + )
{
if ( ! eq_type_nodes ( left . parameters [ i ] . type , right . parameters [ i ] . type ) | |
compare_parameter_types & & left . parameters [ i ] . parameter_type ! = right . parameters [ i ] . parameter_type )
{
return false ;
}
}
return true ;
}
private void check_single_possible_convertion ( ILocation loc , possible_type_convertions_list ptcal )
{
foreach ( possible_type_convertions ptc in ptcal )
{
if ( ptc . second ! = null )
{
AddError ( new PossibleTwoTypeConversionsInFunctionCall ( loc , ptc . first , ptc . second ) ) ;
}
}
}
private void convert_function_call_expressions ( function_node fn , expressions_list exprs ,
possible_type_convertions_list ptcal )
{
for ( int i = 0 ; i < 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 ) ;
exprs . remove_range ( fn . parameters . Count - 1 , exprs . Count - fn . parameters . Count ) ;
//exprs.AddElement(ptcal.var_ref);
//exprs[i] = ptcal.var_ref;
exprs [ i ] = sre ;
break ;
}
if ( ( ptcal [ i ] = = null ) | | ( ptcal [ i ] . first = = null ) | | exprs [ i ] is null_const_node )
{
continue ;
}
expression_node [ ] temp_arr = new expression_node [ 1 ] ;
temp_arr [ 0 ] = exprs [ i ] ;
if ( ptcal [ i ] . first . convertion_method is compiled_constructor_node )
exprs [ i ] = create_compiled_construcor_call ( ptcal [ i ] . first . convertion_method as compiled_constructor_node , get_location ( exprs [ i ] ) , temp_arr ) ;
else
exprs [ i ] = create_simple_function_call ( ptcal [ i ] . first . convertion_method , get_location ( exprs [ i ] ) , temp_arr ) ;
}
//TODO: Можно сделать параметры по умолчанию для откомпилированных функций.
if ( ( exprs . Count < fn . parameters . Count ) & & ( fn . node_kind = = SemanticTree . node_kind . common ) )
{
2018-08-09 12:38:44 +03:00
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 )
2015-05-14 22:35:07 +03:00
{
statements_expression_node sre = new statements_expression_node ( ptcal . snl , ptcal . var_ref , ptcal . var_ref . location ) ;
//exprs.remove_range(fn.parameters.Count - 1, exprs.Count - fn.parameters.Count);
//exprs.AddElement(ptcal.var_ref);
//exprs[i] = ptcal.var_ref;
exprs . AddElement ( sre ) ;
}
common_function_node cfn = ( common_function_node ) fn ;
for ( int j = exprs . Count ; j < cfn . parameters . Count ; j + + )
{
common_parameter cp = ( common_parameter ) cfn . parameters [ j ] ;
if ( cp . default_value ! = null )
exprs . AddElement ( cp . default_value ) ;
}
}
else if ( ( exprs . Count < fn . parameters . Count ) & & ( fn . node_kind = = SemanticTree . node_kind . compiled ) )
{
2018-08-09 12:38:44 +03:00
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 )
2015-05-14 22:35:07 +03:00
{
statements_expression_node sre = new statements_expression_node ( ptcal . snl , ptcal . var_ref , ptcal . var_ref . location ) ;
exprs . AddElement ( sre ) ;
}
//compiled_function_node cfn = (compiled_function_node)fn;
for ( int j = exprs . Count ; j < fn . parameters . Count ; j + + )
{
compiled_parameter cp = ( compiled_parameter ) fn . parameters [ j ] ;
if ( cp . default_value ! = null )
exprs . AddElement ( cp . default_value ) ;
}
}
}
private function_node find_eq_return_value_method_in_list ( function_node fn , function_node_list funcs )
{
foreach ( function_node f in funcs )
{
//Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть.
if ( f = = fn )
{
return f ;
}
if ( function_eq_params_and_result ( fn , f ) )
{
if ( fn . original_function = = f . original_function )
{
return f ;
}
}
}
return null ;
}
public function_node find_eq_method_in_list ( function_node fn , function_node_list funcs )
{
foreach ( function_node f in funcs )
{
//Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть.
if ( f = = fn )
{
return f ;
}
2016-05-16 21:45:03 +03:00
if ( function_eq_params ( fn , f ) )
2015-05-14 22:35:07 +03:00
{
if ( fn . original_function = = f . original_function )
{
return f ;
}
}
}
return null ;
}
2016-05-16 21:45:03 +03:00
public function_node is_exist_eq_method_in_list ( function_node fn , function_node_list funcs )
2015-05-14 22:35:07 +03:00
{
2016-05-16 21:45:03 +03:00
return find_eq_return_value_method_in_list ( fn , funcs ) ;
2015-05-14 22:35:07 +03:00
}
public void init_reference_type ( type_node ctn )
{
SystemLibrary . SystemLibrary . init_reference_type ( ctn ) ;
}
2018-01-16 19:44:01 +03:00
/// <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 ;
}
//Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов.
2018-04-14 18:18:42 +03:00
public function_node select_function ( expressions_list parameters , List < SymbolInfo > functions , location loc , List < SyntaxTree . expression > syntax_nodes_parameters = null )
2017-05-20 21:20:02 +03:00
{
if ( functions = = null )
{
return AddError < function_node > ( new NoFunctionWithThisName ( loc ) ) ;
}
2015-05-14 22:35:07 +03:00
function_node_list set_of_possible_functions = new function_node_list ( ) ;
2017-10-23 11:21:15 +03:00
bool is_alone_method_defined = ( functions . Count ( ) = = 1 ) ;
2018-04-14 18:18:42 +03:00
function_node first_function = functions . FirstOrDefault ( ) . sym_info as function_node ;
2015-05-14 22:35:07 +03:00
bool _is_assigment = first_function . name = = compiler_string_consts . assign_name ;
2018-04-14 18:18:42 +03:00
basic_function_node _tmp_bfn = functions . FirstOrDefault ( ) . sym_info as basic_function_node ;
2015-05-14 22:35:07 +03:00
List < function_node > indefinits = new List < function_node > ( ) ;
2018-04-14 18:18:42 +03:00
foreach ( SymbolInfo function in functions )
2017-05-20 21:20:02 +03:00
{
2015-05-14 22:35:07 +03:00
#if ( DEBUG )
2017-05-20 21:20:02 +03:00
if ( function . sym_info . general_node_type ! = general_node_type . function_node & & function . sym_info . general_node_type ! = general_node_type . property_node )
{
throw new CompilerInternalError ( "Function name is used to define another kind of object." ) ;
}
2015-05-14 22:35:07 +03:00
#endif
function_node fn = null ;
2017-05-20 21:20:02 +03:00
if ( function . sym_info . general_node_type = = general_node_type . property_node )
2015-05-14 22:35:07 +03:00
{
2017-05-20 21:20:02 +03:00
fn = ( function . sym_info as property_node ) . get_function ;
2015-05-14 22:35:07 +03:00
}
else
2017-05-20 21:20:02 +03:00
fn = ( function_node ) function . sym_info ;
2015-05-14 22:35:07 +03:00
if ( fn . node_kind = = node_kind . indefinite )
{
indefinits . Add ( fn ) ;
}
2017-10-23 11:21:15 +03:00
else if ( fn . node_kind = = node_kind . common )
2017-05-20 21:20:02 +03:00
{
common_function_node cfn = ( common_function_node ) fn ;
if ( ( parameters . Count > = cfn . parameters . Count - cfn . num_of_default_variables ) & &
( parameters . Count < = cfn . parameters . Count ) | | parameters . Count = = 0 & & cfn . parameters . Count = = 1 & & cfn . parameters [ 0 ] . is_params )
{
if ( is_exist_eq_method_in_list ( fn , set_of_possible_functions ) ! = null )
{
2015-05-14 22:35:07 +03:00
if ( set_of_possible_functions . Count > 0 )
if ( set_of_possible_functions [ 0 ] is basic_function_node )
{
set_of_possible_functions . remove ( set_of_possible_functions [ 0 ] ) ;
set_of_possible_functions . AddElement ( fn ) ;
}
2017-05-20 21:20:02 +03:00
continue ;
}
set_of_possible_functions . AddElement ( fn ) ;
}
}
else
{
2015-05-14 22:35:07 +03:00
//TODO: Здесь нужно поправить, если создавать возможность вызова метода с параметрами по умолчанию из откомпилированной dll.
2017-05-20 21:20:02 +03:00
if ( parameters . Count = = fn . parameters . Count )
{
2015-05-14 22:35:07 +03:00
function_node func = null ;
2017-05-20 21:20:02 +03:00
if ( ( func = is_exist_eq_method_in_list ( fn , set_of_possible_functions ) ) ! = null )
{
2015-05-14 22:35:07 +03:00
if ( ! eq_type_nodes ( fn . return_value_type , func . return_value_type ) )
{
set_of_possible_functions [ set_of_possible_functions . IndexOf ( func ) ] = fn ;
2017-05-20 21:20:02 +03:00
2015-05-14 22:35:07 +03:00
}
continue ;
2017-05-20 21:20:02 +03:00
}
set_of_possible_functions . AddElement ( fn ) ;
}
}
2015-05-14 22:35:07 +03:00
if ( parameters . Count > fn . parameters . Count )
{
if ( fn . parameters . Count > 0 )
{
if ( ( fn . parameters [ fn . parameters . Count - 1 ] ) . is_params )
{
//+DS ms0105
if ( is_exist_eq_method_in_list ( fn , set_of_possible_functions ) ! = null )
{
continue ;
}
//-DS
set_of_possible_functions . AddElement ( fn ) ;
}
}
}
2018-08-09 12:38:44 +03:00
//else if ((parameters.Count == 0 && fn.parameters.Count == 1) && fn.parameters[0].is_params && !set_of_possible_functions.Contains(fn))
2018-08-06 14:49:41 +03:00
// SSM 6.08.18 - так просто исправить не получается - видимо, сопоставление параметров работает неверно
2018-08-09 12:38:44 +03:00
else if ( ( parameters . Count = = fn . parameters . Count - 1 ) & & fn . parameters [ fn . parameters . Count - 1 ] . is_params & & ! set_of_possible_functions . Contains ( fn ) )
2015-05-14 22:35:07 +03:00
set_of_possible_functions . AddElement ( fn ) ;
else if ( fn . num_of_default_parameters ! = 0 & & parameters . Count > = fn . parameters . Count - fn . num_of_default_parameters )
{
if ( ! set_of_possible_functions . Contains ( fn ) )
set_of_possible_functions . AddElement ( fn ) ;
}
else if ( parameters . Count = = 1 & & fn is common_namespace_function_node & & ( fn as common_namespace_function_node ) . ConnectedToType ! = null & & fn . parameters . Count = = 2 & & fn . parameters [ 1 ] . is_params )
set_of_possible_functions . AddElement ( fn ) ;
2015-12-31 17:11:25 +03:00
else if ( parameters . Count = = 1 & & fn is compiled_function_node & & ( fn as compiled_function_node ) . ConnectedToType ! = null & & fn . parameters . Count = = 2 & & fn . parameters [ 1 ] . is_params )
if ( ! set_of_possible_functions . Contains ( fn ) )
set_of_possible_functions . AddElement ( fn ) ;
2017-05-20 21:20:02 +03:00
}
2015-05-14 22:35:07 +03:00
2017-05-20 21:20:02 +03:00
if ( set_of_possible_functions . Count = = 0 & & indefinits . Count = = 0 )
{
2017-12-31 17:25:22 +03:00
return AddError < function_node > ( new NoFunctionWithSameParametresNum ( loc , is_alone_method_defined , first_function ) ) ;
2017-05-20 21:20:02 +03:00
}
2015-05-14 22:35:07 +03:00
//(ssyy) Инициализируем is_alone_defined
FailedWhileTryingToCompileLambdaBodyWithGivenParametersException lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = null ;
if ( set_of_possible_functions . Count = = 1 & & indefinits . Count = = 0 )
{
is_alone_method_defined = true ;
}
//(ssyy) Инстанцируем дженерики
for ( int i = set_of_possible_functions . Count - 1 ; i > - 1 ; - - i )
{
function_node func = set_of_possible_functions [ i ] ;
if ( func . is_generic_function )
{
try
{
function_node inst = generic_convertions . DeduceFunction ( func , parameters ,
2018-05-23 20:06:20 +03:00
is_alone_method_defined , syntax_tree_visitor . context , loc , syntax_nodes_parameters ) ;
2015-05-14 22:35:07 +03:00
if ( inst = = null )
{
set_of_possible_functions . remove_at ( i ) ;
}
else
{
set_of_possible_functions [ i ] = inst ;
}
}
catch ( FailedWhileTryingToCompileLambdaBodyWithGivenParametersException exc ) //lroman Отлавливаем последнее исключение, которое возникло при попытке скомпилировать тело лямбды с заданными типами параметров
{
set_of_possible_functions . remove_at ( i ) ;
lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = exc ;
}
2018-03-11 14:16:27 +03:00
catch ( Errors . Error err )
{
return AddError < function_node > ( err ) ;
}
2015-05-14 22:35:07 +03:00
}
}
if ( lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException ! = null
& & set_of_possible_functions . Count = = 0
& & indefinits . Count = = 0 )
{
throw lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException . ExceptionOnCompileBody ; // Если перебрали все, но ничто не подошло, то кидаем последнее исключение
}
if ( set_of_possible_functions . Count = = 0 & & indefinits . Count = = 0 )
{
2016-04-14 21:16:31 +03:00
return AddError < function_node > ( loc , "CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS" , first_function . name ) ;
2015-05-14 22:35:07 +03:00
}
possible_type_convertions_list_list tcll = new possible_type_convertions_list_list ( ) ;
2015-12-27 15:24:25 +03:00
for ( int i = 0 ; i < set_of_possible_functions . Count ; i + + )
{
2016-05-16 21:45:03 +03:00
Errors . Error err = null ;
2015-12-27 15:24:25 +03:00
possible_type_convertions_list tc = get_conversions ( parameters , set_of_possible_functions [ i ] . parameters ,
2016-05-16 21:45:03 +03:00
is_alone_method_defined , loc , out err ) ;
if ( err ! = null )
return AddError < function_node > ( err ) ;
2015-12-27 15:24:25 +03:00
//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 )
2016-05-16 21:45:03 +03:00
{
err = null ;
2015-12-27 15:24:25 +03:00
tc = get_conversions ( el , set_of_possible_functions [ i ] . parameters ,
2016-05-16 21:45:03 +03:00
is_alone_method_defined , loc , out err ) ;
if ( err ! = null )
return AddError < function_node > ( err ) ;
}
2017-05-20 21:20:02 +03:00
2015-12-27 15:24:25 +03:00
}
tcll . AddElement ( tc ) ;
}
2015-05-14 22:35:07 +03:00
2017-05-20 21:20:02 +03:00
int j = 0 ;
2016-12-06 23:34:35 +03:00
while ( j < set_of_possible_functions . Count )
{
if ( tcll [ j ] = = null & & set_of_possible_functions [ j ] . node_kind ! = node_kind . indefinite )
{
tcll . remove_at ( j ) ;
set_of_possible_functions . remove_at ( j ) ;
}
else
{
j + + ;
}
}
2015-05-14 22:35:07 +03:00
2017-05-20 21:20:02 +03:00
if ( set_of_possible_functions . Count = = 0 & & indefinits . Count = = 0 )
{
2015-05-14 22:35:07 +03:00
if ( _is_assigment & & parameters . Count = = 2 )
2015-10-18 14:35:44 +03:00
return AddError < function_node > ( new CanNotConvertTypes ( parameters [ 1 ] , parameters [ 1 ] . type , parameters [ 0 ] . type , parameters [ 1 ] . location ) ) ;
2015-05-14 22:35:07 +03:00
if ( _tmp_bfn ! = null & & parameters . Count = = 2 )
2017-05-20 21:20:02 +03:00
return AddError < function_node > ( new OperatorCanNotBeAppliedToThisTypes ( _tmp_bfn . name , parameters [ 0 ] , parameters [ 1 ] , loc ) ) ;
return AddError < function_node > ( new NoFunctionWithSameArguments ( loc , is_alone_method_defined ) ) ;
}
2015-05-14 22:35:07 +03:00
2017-05-20 21:20:02 +03:00
bool remove = true ;
while ( remove )
{
if ( set_of_possible_functions . Count = = 1 )
{
check_single_possible_convertion ( loc , tcll [ 0 ] ) ;
convert_function_call_expressions ( set_of_possible_functions [ 0 ] , parameters , tcll [ 0 ] ) ;
return set_of_possible_functions [ 0 ] ;
}
remove = false ;
2015-08-09 16:25:11 +03:00
var i = 0 ;
2017-05-20 21:20:02 +03:00
while ( i < set_of_possible_functions . Count - 1 )
2015-08-09 16:25:11 +03:00
{
2017-05-20 21:20:02 +03:00
j = i + 1 ;
2015-08-09 16:25:11 +03:00
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 ] ) ;
2016-03-20 16:23:41 +03:00
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 ;
}
}
2015-08-09 16:25:11 +03:00
if ( mc = = method_compare . greater_method )
{
tcll . remove_at ( j ) ;
set_of_possible_functions . remove_at ( j ) ;
remove = true ;
}
else if ( mc = = method_compare . less_method )
{
tcll [ i ] = tcll [ j ] ;
set_of_possible_functions [ i ] = set_of_possible_functions [ j ] ;
tcll . remove_at ( j ) ;
set_of_possible_functions . remove_at ( j ) ;
remove = true ;
}
else
{
j + + ;
}
}
i + + ;
}
}
2015-05-14 22:35:07 +03:00
//Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений
//в дальнейшем может вызвать странное поведение, это надо проверить
if ( set_of_possible_functions . Count = = 2 & & indefinits . Count = = 0 )
if ( set_of_possible_functions [ 0 ] is basic_function_node & & set_of_possible_functions [ 1 ] is basic_function_node )
return set_of_possible_functions [ 0 ] ;
if ( indefinits . Count > 0 )
{
if ( indefinits . Count = = 1 & & set_of_possible_functions . Count = = 0 )
{
return indefinits [ 0 ] ;
}
indefinits . AddRange ( set_of_possible_functions ) ;
return new indefinite_functions_set ( indefinits ) ;
}
bool exist_indefinite_parameter = false ;
foreach ( expression_node par in parameters )
{
if ( par . type . depended_from_indefinite )
{
exist_indefinite_parameter = true ;
break ;
}
}
if ( exist_indefinite_parameter )
{
indefinits . AddRange ( set_of_possible_functions ) ;
return new indefinite_functions_set ( indefinits ) ;
}
2015-10-18 14:35:44 +03:00
2016-02-21 19:12:52 +03:00
SortedDictionary < int , List < function_node > > distances = new SortedDictionary < int , List < function_node > > ( ) ;
2016-05-16 21:45:03 +03:00
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 ) ;
2017-05-26 15:13:17 +03:00
if ( best_function . return_value_type . is_standard_type & & fn . return_value_type . is_standard_type )
2016-05-16 21:45:03 +03:00
{
2017-05-26 15:13:17 +03:00
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
2016-05-16 21:45:03 +03:00
{
2017-05-26 15:13:17 +03:00
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 ) ;
2016-05-16 21:45:03 +03:00
}
}
}
}
foreach ( function_node fn in to_remove )
{
set_of_possible_functions . remove ( fn ) ;
}
2016-07-22 13:00:58 +03:00
// Формирование словаря списков функций с одинаковым значением расстояния
2017-11-16 23:10:30 +03:00
// 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. В с е подходят :)
2017-05-20 21:20:02 +03:00
foreach ( function_node fn in set_of_possible_functions )
2016-02-21 19:12:52 +03:00
{
int distance = 0 ;
for ( int i = 0 ; i < parameters . Count ; i + + )
{
type_node from = parameters [ i ] . type ;
2017-05-20 21:20:02 +03:00
type_node to = fn . parameters [ Math . Min ( i , fn . parameters . Count - 1 ) ] . type ;
2016-02-21 19:12:52 +03:00
if ( fn . parameters [ Math . Min ( i , fn . parameters . Count - 1 ) ] . is_params )
to = to . element_type ;
2016-07-22 13:00:58 +03:00
// ToDo: необходимо сделать более детальную get_type_distance.
// Сейчас для функциональных параметров она всегда возвращает 1000
2016-02-21 19:12:52 +03:00
distance + = get_type_distance ( from , to ) ;
}
2017-05-20 21:20:02 +03:00
2016-05-16 21:45:03 +03:00
/ * 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 ;
} * /
2016-02-21 19:12:52 +03:00
List < function_node > lst ;
2017-05-20 21:20:02 +03:00
if ( distances . TryGetValue ( distance , out lst ) )
2016-02-21 19:12:52 +03:00
{
lst . Add ( fn ) ;
}
else
{
lst = new List < function_node > ( ) ;
lst . Add ( fn ) ;
distances [ distance ] = lst ;
}
}
2016-07-22 13:00:58 +03:00
foreach ( int dist in distances . Keys ) // Дистанции упорядочены по возрастанию. Логика тут немного странная:
2017-05-20 21:20:02 +03:00
// если для какой-то минимальной дистанции найдется ровно одна функция, то она и выбирается
// если две и больше - то они пробрасываются и мы переходим к бОльшей дистанции
2016-02-21 19:12:52 +03:00
{
List < function_node > funcs = distances [ dist ] ;
if ( funcs . Count = = 1 )
{
2016-05-16 21:45:03 +03:00
Errors . Error err = null ;
possible_type_convertions_list tcl = get_conversions ( parameters , funcs [ 0 ] . parameters , true , loc , out err ) ;
if ( err ! = null )
return AddError < function_node > ( err ) ;
2016-02-21 19:12:52 +03:00
convert_function_call_expressions ( funcs [ 0 ] , parameters , tcl ) ;
return funcs [ 0 ] ;
}
2018-01-15 10:17:02 +03:00
2018-01-16 19:44:01 +03:00
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 ;
var bools = Enumerable . Range ( 1 , funcs . Count ( ) ) . Select ( x = > true ) . ToList ( ) ;
var AllOK = true ;
for ( var i = 0 ; i < ParamsCount ; i + + )
{
// Хочу взять проекцию всех функций на i-тый параметр
var parsi = funcs . Select ( f = > f . parameters [ i ] . type ) ;
if ( parsi . Any ( p = > ! IsFuncT ( p ) ) ) // Если какой-то параметр не функция, то пробросим е г о
continue ;
var argss = funcs . Select ( f = > get_type ( f . parameters [ i ] . type ) . GetGenericArguments ( ) ) . ToArray ( ) ; // последовательность массивов параметров Func
var cnts = argss . Select ( a = > a . Count ( ) ) ;
var fpi = funcs [ 0 ] . parameters [ i ] ;
var cnt = get_type ( fpi . type ) . GetGenericArguments ( ) . Count ( ) ;
// Проверю, что у остальных функций столько же параметров
if ( cnts . Any ( c = > c ! = cnts . First ( ) ) ) // если нет, то - всё - это ошибка - многозначность. Хотя тут уже не должно быть
{
AllOK = false ;
break ;
}
// Цикл по параметрам Func кроме последнего
for ( var k = 0 ; k < cnt - 1 ; k + + )
{
var kpars = funcs . Select ( f = > get_type ( f . parameters [ i ] . type ) . GetGenericArguments ( ) [ k ] ) ;
Type p0 = kpars . First ( ) ;
bool bb = kpars . All ( p = > p . Equals ( p0 ) ) ;
if ( ! bb )
{
AllOK = false ;
break ;
}
}
if ( ! AllOK )
break ;
var kres = funcs . Select ( f = > get_type ( f . parameters [ i ] . type ) . GetGenericArguments ( ) [ cnt - 1 ] ) . ToArray ( ) ;
//if (funcs[0].is_extension_method)
var fldiResType = funcs [ 0 ] . is_extension_method ? // странно, но всегда кво параметров в syntax_nodes_parameters на 1 меньше. Иначе падает
( ( syntax_nodes_parameters [ i - 1 ] as SyntaxTree . function_lambda_definition ) . RealSemTypeOfResult as compiled_type_node ) . compiled_type :
( ( syntax_nodes_parameters [ i - 1 ] as SyntaxTree . function_lambda_definition ) . RealSemTypeOfResult as compiled_type_node ) . compiled_type ;
for ( int n = 0 ; n < bools . Count ; n + + )
{
if ( ! fldiResType . Equals ( kres [ n ] ) )
bools [ n ] = false ;
}
//var rettype_i =
}
if ( AllOK )
if ( bools . Count ( x = > x = = true ) = = 1 ) // у р р а ! нашлась ровно одна функция! мы победили!
{
var ind = bools . IndexOf ( true ) ;
return funcs [ ind ] ;
}
/// Проба 15.01.18 - потом удалить
/ * {
var f1 = funcs [ 0 ] ;
var f2 = funcs [ 1 ] ;
for ( int i = 0 ; i < parameters . Count ; i + + )
{
type_node f1i = f1 . parameters [ i ] . type ;
type_node f2i = f2 . parameters [ i ] . type ;
var f1ic = get_compiled_type_node ( f1i ) ;
var f2ic = get_compiled_type_node ( f2i ) ;
if ( f1ic = = null | | f2ic = = null )
break ;
Type ct1 = f1ic . compiled_type ;
Type ct2 = f2ic . compiled_type ;
if ( IsFunc ( ct1 ) & & IsFunc ( ct2 ) )
{
var l1 = ct1 . GetGenericArguments ( ) [ 0 ] ;
var l2 = ct2 . GetGenericArguments ( ) [ 0 ] ;
var b = l1 . Equals ( l2 ) ;
var b1 = l1 = = l2 ;
}
//var p = syntax_nodes_parameters[i];
}
} * /
2018-01-15 10:17:02 +03:00
// Вот здесь нужен анализ всех оставшихся функций.
// Если они отличаются только функциональными параметрами и у этих параметров
// одинаковый тип параметров (они уже инстанцированы!), то надо еще раз
// вызвать то, что вызывается в DeduceFunction чтобы установить, каков тип возвращаемого значения лямбды, после чего
// выбрать либо функцию из оставшихся с ровно совпадающим типом лямбды либо с ближайшим
// (остались только те, к которым можно преобразовать)
// Некоторая проблема будет если лямбд останется несколько и расстояния до результата будут разными и ненулевыми везде
2018-08-06 13:54:40 +03:00
if ( funcs . Count > = 2 ) // SSM - это ужасный способ устранения б а г а #236 Range(1,10).Sum(e -> e); Для хорошего способа весь код выбора версий функций для делегатов надо переписывать
2016-07-22 13:00:58 +03:00
{
var f1 = funcs [ 0 ] ;
var f2 = funcs [ 1 ] ;
if ( f1 . parameters . Count = = f2 . parameters . Count )
{
2017-05-20 21:20:02 +03:00
for ( var i = 0 ; i < f1 . parameters . Count ; i + + )
2016-07-22 13:00:58 +03:00
{
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 ;
}
2016-12-20 22:34:44 +03:00
var ctn2 = p2 as compiled_type_node ;
2016-07-22 13:00:58 +03:00
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 ;
2017-03-16 23:52:40 +03:00
if ( c ! = 0 & & ( ct1 . GetGenericArguments ( ) . Last ( ) . FullName = = null | | ct1 . GetGenericArguments ( ) . Last ( ) . FullName . StartsWith ( "System.Nullable" ) ) )
2016-07-22 13:00:58 +03:00
return f2 ;
}
System . Type ct2 = ctn2 . compiled_type ;
if ( ct2 . IsGenericType & & ct2 . FullName . StartsWith ( "System.Func" ) )
{
var c = ct2 . GetGenericArguments ( ) . Length ;
2017-03-16 23:52:40 +03:00
if ( c ! = 0 & & ( ct2 . GetGenericArguments ( ) . Last ( ) . FullName = = null | | ct2 . GetGenericArguments ( ) . Last ( ) . FullName . StartsWith ( "System.Nullable" ) ) )
2016-07-22 13:00:58 +03:00
return f1 ;
}
}
2018-01-15 10:17:02 +03:00
2016-12-20 22:34:44 +03:00
/ * 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 ;
}
} * /
2016-07-22 13:00:58 +03:00
}
2017-05-20 21:20:02 +03:00
2016-07-22 13:00:58 +03:00
}
2016-02-21 19:12:52 +03:00
}
2017-05-20 21:20:02 +03:00
return AddError < function_node > ( new SeveralFunctionsCanBeCalled ( loc , set_of_possible_functions ) ) ;
}
2015-05-14 22:35:07 +03:00
2016-02-21 19:12:52 +03:00
private int get_type_distance ( type_node from , type_node to )
{
if ( from = = to )
return 0 ;
2017-03-08 22:21:05 +03:00
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 ;
2018-08-06 22:35:21 +03:00
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 ;
}
}
}
}
2018-08-19 20:29:35 +03:00
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 ;
}
}
2016-02-21 19:12:52 +03:00
type_compare tc = type_table . compare_types ( from , to ) ;
if ( tc = = type_compare . non_comparable_type )
return 1000 ;
if ( ! from . IsInterface & & to . IsInterface )
2018-08-19 20:29:35 +03:00
return 200 ;
2016-02-21 19:12:52 +03:00
if ( tc = = type_compare . less_type )
2018-08-19 20:29:35 +03:00
{
return 100 ;
}
2016-02-21 19:12:52 +03:00
if ( tc = = type_compare . greater_type )
2018-08-19 20:29:35 +03:00
return 300 ;
2016-02-21 19:12:52 +03:00
return 1000 ;
}
2018-08-19 20:29:35 +03:00
2015-05-14 22:35:07 +03:00
private function_node is_exist_eq_return_value_method ( function_node fn , function_node_list funcs )
{
fn = find_eq_return_value_method_in_list ( fn , funcs ) ;
return fn ;
}
private string get_return_variable_name ( string function_name )
{
return ( compiler_string_consts . function_return_value_prefix + function_name ) ;
}
2017-10-23 11:21:15 +03:00
public void create_function_return_variable ( common_function_node cfn , SymbolInfo ret_var )
2017-05-20 21:20:02 +03:00
{
2015-05-14 22:35:07 +03:00
if ( ! SemanticRules . AddResultVariable )
return ;
//#if (DEBUG)
2017-05-20 21:20:02 +03:00
if ( cfn . return_value_type = = null )
{
2015-05-14 22:35:07 +03:00
return ;
2017-05-20 21:20:02 +03:00
//throw new CompilerInternalError("Procedure can not return value");
}
2015-05-14 22:35:07 +03:00
//#endif
if ( cfn . return_variable ! = null )
{
if ( ret_var ! = null )
2017-05-20 21:20:02 +03:00
ret_var . sym_info = cfn . return_variable ;
2015-05-14 22:35:07 +03:00
return ;
}
2017-05-20 21:20:02 +03:00
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 ) ;
2015-05-14 22:35:07 +03:00
if ( ret_var ! = null )
{
ret_var . sym_info = cfn . return_variable ;
}
2017-05-20 21:20:02 +03:00
}
2015-05-14 22:35:07 +03:00
2017-05-20 21:20:02 +03:00
public void check_node_parser_error ( SyntaxTree . syntax_tree_node tn )
2015-05-14 22:35:07 +03:00
{
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 )
{
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 ) ;
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 ;
}
return ret_type ;
}
2018-07-20 22:13:07 +03:00
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 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 bool is_value_real_type ( type_node tn )
{
return tn = = SystemLibrary . SystemLibrary . double_type | |
tn = = SystemLibrary . SystemLibrary . float_type
;
}
public 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 ( ( int ) n1 < = ( int ) int_types . integer_type & & ( int ) n2 < = ( int ) int_types . integer_type ) return SystemLibrary . SystemLibrary . integer_type ;
if ( n1 = = n2 ) return tn1 ;
// Первый тип - меньше
if ( ( int ) n2 = = ( int ) int_types . uint64_type )
return SystemLibrary . SystemLibrary . uint64_type ;
if ( ( int ) n2 = = ( int ) int_types . int64_type )
{
if ( ( int ) n1 < = ( int ) int_types . integer_type )
return SystemLibrary . SystemLibrary . int64_type ;
else return SystemLibrary . SystemLibrary . uint64_type ;
}
if ( ( int ) n2 = = ( int ) int_types . uint_type ) // longword
{
if ( ( int ) n1 = = 0 | | ( int ) n1 = = 2 | | ( int ) n1 = = 4 )
return SystemLibrary . SystemLibrary . int64_type ;
if ( ( int ) n1 = = 1 | | ( int ) n1 = = 3 )
return SystemLibrary . SystemLibrary . uint_type ; // longword
// n1 = 6 или 7
return SystemLibrary . SystemLibrary . uint64_type ;
}
return null ; // это вхолостую
}
}
2015-05-14 22:35:07 +03:00
}