pascalabcnet/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs
Бондарев Иван 5e75a1c66f bug fix #95, #155
2016-05-16 20:45:03 +02:00

2147 lines
94 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
//Некоторые алгоритмы . В основном выбор перегруженного метода. Сильно связан с syntax_tree_visitor.
using System;
using System.Collections.Generic;
using PascalABCCompiler.SemanticTree;
using PascalABCCompiler.TreeRealization;
namespace PascalABCCompiler.TreeConverter
{
public class convertion_data_and_alghoritms
{
internal SymbolTable.TreeConverterSymbolTable symtab=SymbolTable.SymbolTableController.CurrentSymbolTable;
private PascalABCCompiler.Errors.SyntaxError _parser_error;
private syntax_tree_visitor _stv;
private type_constructor _type_constructor;
public statement_list_stack statement_list_stack = new statement_list_stack();
//private special_operation_kind _current_operation_kind= special_operation_kind.none;
public convertion_data_and_alghoritms(syntax_tree_visitor stv)
{
type_table.type_table_function_call_maker = create_simple_function_call;
_stv=stv;
_type_constructor = new type_constructor(this);
SystemLibrary.SystemLibrary.type_constructor = _type_constructor;
}
private void AddError(Errors.Error err)
{
syntax_tree_visitor.AddError(err);
}
private T AddError<T>(Errors.Error err)
{
syntax_tree_visitor.AddError(err, true);
return default(T);
}
private T AddError<T>(location loc, string ErrString, params string[] values)
{
syntax_tree_visitor.AddError(loc, ErrString, values);
return default(T);
}
private void AddError(location loc, string ErrString, params string[] values)
{
syntax_tree_visitor.AddError(loc, ErrString, values);
}
public void reset()
{
symtab.Clear();
_type_constructor.reset();
statement_list_stack.clear();
arr_nums = 0;
//_current_operation_kind = special_operation_kind.none;
}
/*
public special_operation_kind current_operation_kind
{
get
{
return _current_operation_kind;
}
set
{
_current_operation_kind = value;
}
}
*/
internal void statement_list_stack_push(statements_list sl)
{
sl.Scope = new SymbolTable.BlockScope(symbol_table, syntax_tree_visitor.context.CurrentScope);
statement_list_stack.push(sl);
}
internal SymbolTable.Scope create_block_scope()
{
return new SymbolTable.BlockScope(symbol_table, syntax_tree_visitor.context.CurrentScope);
}
internal void statement_list_stack_push(statements_list sl, SymbolTable.Scope Scope)
{
sl.Scope = Scope;
statement_list_stack.push(sl);
}
internal statements_list statement_list_stack_pop()
{
return statement_list_stack.pop();
}
public type_constructor type_constructor
{
get
{
return _type_constructor;
}
}
public PascalABCCompiler.Errors.SyntaxError parser_error
{
get
{
return _parser_error;
}
set
{
_parser_error = value;
}
}
public System.Collections.Hashtable bad_nodes_in_syntax_tree;
public SymbolTable.TreeConverterSymbolTable symbol_table
{
get
{
return symtab;
}
}
//TODO: Наверно это свойство вообще не нужно.
public syntax_tree_visitor syntax_tree_visitor
{
get
{
return _stv;
}
}
//TODO: Избавиться от дублирования метода.
public location get_location(semantic_node sn)
{
SemanticTree.ILocated iloc=sn as SemanticTree.ILocated;
if (iloc==null)
{
return null;
}
document doc = _stv.CurrentDocument;
location loc=null;
//DarkStar changed
//В PCU не сохраняются location некоторых конструкций, например
//числовых констант итд. Поэтому необохдимо делать эту проверку.
//Коля может всетаки нужно хранить?
if (iloc.Location != null)
loc = new location(iloc.Location.begin_line_num, iloc.Location.begin_column_num,
iloc.Location.end_line_num, iloc.Location.end_column_num, doc);
return loc;
}
//TODO: Избавиться от этого метода. Везде должен быть только location (а не ILocation).
private location loc_to_loc(SemanticTree.ILocation l)
{
if (l == null)
{
return null;
}
document d = new document(l.document.file_name);
if (d == null)
d = syntax_tree_visitor.CurrentDocument;
location loc = new location(l.begin_line_num, l.begin_column_num, l.end_line_num, l.end_column_num, d);
return loc;
}
//TODO: Вообще нужен-ли этот набор методов (create_..._function_call)?
private basic_function_call create_basic_function_call(basic_function_node bfn,SemanticTree.ILocation loc,params expression_node[] exprs)
{
basic_function_call bfc=new basic_function_call(bfn,loc_to_loc(loc));
bfc.parameters.AddRange(exprs);
return bfc;
}
private common_namespace_function_call create_common_namespace_function_call(common_namespace_function_node cnfn,
SemanticTree.ILocation loc,params expression_node[] exprs)
{
common_namespace_function_call cnc=new common_namespace_function_call(cnfn,loc_to_loc(loc));
cnc.parameters.AddRange(exprs);
return cnc;
}
private common_static_method_call create_common_static_method_call(common_method_node cmn,SemanticTree.ILocation loc,
params expression_node[] exprs)
{
#if (DEBUG)
if (cmn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Not static method can not be called as static");
}
#endif
common_static_method_call csmc=new common_static_method_call(cmn,loc_to_loc(loc));
csmc.parameters.AddRange(exprs);
return csmc;
}
public variable_reference CreateVariableReference(var_definition_node vd, location loc)
{
switch (vd.semantic_node_type)
{
case semantic_node_type.local_variable:
return new local_variable_reference((local_variable)vd, 0, loc);
case semantic_node_type.class_field:
if (vd.polymorphic_state == polymorphic_state.ps_static)
return new static_class_field_reference((class_field)vd, loc);
else
return new class_field_reference((class_field)vd, syntax_tree_visitor.GetCurrentObjectReference((vd as class_field).cont_type.Scope,vd,loc), loc);
case semantic_node_type.namespace_variable:
return new namespace_variable_reference((namespace_variable)vd, loc);
case semantic_node_type.local_block_variable:
return new local_block_variable_reference((local_block_variable)vd, loc);
}
throw new NotSupportedError(loc);
}
private common_in_function_function_call create_common_in_function_function_call(common_in_function_function_node cfn,
int static_depth,location loc,params expression_node[] exprs)
{
common_in_function_function_call cc=new common_in_function_function_call(cfn,static_depth,loc);
cc.parameters.AddRange(exprs);
return cc;
}
private common_method_call create_common_method_call(common_method_node cmn,location loc,expression_node obj,
params expression_node[] exprs)
{
#if (DEBUG)
if (cmn.polymorphic_state==SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Static method can not be called with type");
}
#endif
common_method_call cmc=new common_method_call(cmn,obj,loc);
cmc.virtual_call = !syntax_tree_visitor.inherited_ident_processing;
cmc.parameters.AddRange(exprs);
return cmc;
}
private compiled_function_call create_compiled_function_call(compiled_function_node cfn, location loc,
expression_node obj,params expression_node[] exprs)
{
#if (DEBUG)
if (cfn.polymorphic_state==SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Static method can not be called with type");
}
#endif
compiled_function_call cfc=new compiled_function_call(cfn,obj,loc);
cfc.virtual_call = !syntax_tree_visitor.inherited_ident_processing;
cfc.parameters.AddRange(exprs);
return cfc;
}
private compiled_static_method_call create_compiled_static_method_call(compiled_function_node cfn,
location loc, params expression_node[] exprs)
{
#if (DEBUG)
if (cfn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Not static method can not be called as static");
}
#endif
compiled_static_method_call csmc=new compiled_static_method_call(cfn,loc);
csmc.parameters.AddRange(exprs);
return csmc;
}
public expression_node create_compiled_construcor_call(compiled_constructor_node fn, location loc, params expression_node[] exprs)
{
compiled_constructor_call ccc = new compiled_constructor_call(fn, loc);
ccc.parameters.AddRange(exprs);
return ccc;
}
//Метод только для внутнреннего использования.
//НЕ ПРЕОБРАЗУЕТ ТИПЫ. Только создает узел вызова метода.
//Этот метод и используется для создания узлов преобразования типов.
//TODO: Переименовать.
public expression_node create_simple_function_call(function_node fn, location loc, params expression_node[] exprs)
{
if (fn.compile_time_executor != null)
{
expression_node ex = fn.compile_time_executor(loc, exprs);
if (ex != null)
{
return ex;
}
}
switch (fn.semantic_node_type)
{
case semantic_node_type.basic_function_node:
{
return create_basic_function_call((basic_function_node)fn, loc, exprs);
}
case semantic_node_type.common_namespace_function_node:
{
return create_common_namespace_function_call((common_namespace_function_node)fn, loc, exprs);
}
case semantic_node_type.common_method_node:
{
common_method_node cmn = (common_method_node)fn;
if (cmn.polymorphic_state != SemanticTree.polymorphic_state.ps_static)
{
break;
}
return create_common_static_method_call(cmn, loc, exprs);
}
/*
case semantic_node_type.pseudo_function:
{
pseudo_function pf=(pseudo_function)fn;
return pf.execute_pseudo_function_algorithm(loc,exprs);
}
*/
case semantic_node_type.common_in_function_function_node: break;
case semantic_node_type.compiled_function_node:
{
compiled_function_node cfn = (compiled_function_node)fn;
if (cfn.polymorphic_state != SemanticTree.polymorphic_state.ps_static)
{
break;
}
return create_compiled_static_method_call(cfn, loc, exprs);
}
case semantic_node_type.compiled_constructor_node:
{
compiled_constructor_call ccc = new compiled_constructor_call((compiled_constructor_node)fn,loc);
ccc.parameters.AddRange(exprs);
return ccc;
}
case semantic_node_type.indefinite_definition_node:
{
indefinite_function_call ifc = new indefinite_function_call(fn, loc);
ifc.parameters.AddRange(exprs);
return ifc;
}
default: throw new CompilerInternalError("Unknown function type");
}
throw new CanNotReferenceToNonStaticMethodWithType(fn.name, loc);
}
public expression_node create_method_call(function_node fn, location loc, expression_node obj, params expression_node[] exprs)
{
if (fn.compile_time_executor != null)
{
expression_node ex = fn.compile_time_executor(loc, exprs);
if (ex != null)
{
return ex;
}
}
switch (fn.semantic_node_type)
{
case semantic_node_type.common_method_node:
{
common_method_node cmn = (common_method_node)fn;
return create_common_method_call(cmn, loc, obj, exprs);
}
case semantic_node_type.compiled_function_node:
{
compiled_function_node cfn = (compiled_function_node)fn;
return create_compiled_function_call(cfn, loc, obj, exprs);
}
default: throw new CompilerInternalError("Unknown function type");
}
}
/// <summary>
/// Этот метод вызывается если мы встречаем простой вызов функии, например f(1).
/// Он определяет является ли эта функция методом класса, вложенной функцией и т.д. и создает соответствующее обращение.
/// Например, для метода класса он добавляет this, а для вложенной функции вычисляет статическую глубину.
/// </summary>
/// <param name="exprs">Список параметров.</param>
/// <param name="si">Список методов.</param>
/// <param name="loc">Расположение вызова.</param>
/// <param name="converted_type">Тип в котором мы находимся. null, если мы вне типа.</param>
/// <param name="top_function">Функция в которой мы находимся.</param>
/// <param name="allow_procedure">Может ли это быть вызов процедуры. false если вызов стоит в выражении или правой части опреатора присваивания.</param>
/// <returns>Возвращает узел вызова метода.</returns>
public expression_node create_full_function_call(expressions_list exprs, SymbolInfo si, location loc,
common_type_node converted_type, common_function_node top_function, bool allow_procedure)
{
function_node fn = select_function(exprs, si, loc);
//allow_procedure = true;
if ((!allow_procedure) && (fn.return_value_type == null))
{
throw new SimpleSemanticError(loc, "FUNCTION_EXPECTED_PROCEDURE_{0}_MEET", fn.name);
}
expression_node expr_node = null;
switch (fn.semantic_node_type)
{
case semantic_node_type.basic_function_node:
case semantic_node_type.common_namespace_function_node:
{
expr_node = create_simple_function_call(fn, loc, exprs.ToArray());
break;
}
case semantic_node_type.common_method_node:
case semantic_node_type.compiled_function_node:
{
SemanticTree.IClassMemberNode icmn = (SemanticTree.IClassMemberNode)fn;
if (icmn.polymorphic_state == SemanticTree.polymorphic_state.ps_static)
{
expr_node = create_simple_function_call(fn, loc, exprs.ToArray());
break;
}
//expression_node tn = new this_node(converted_type,loc);
base_function_call cmc = null;
switch (fn.semantic_node_type)
{
case semantic_node_type.common_method_node:
{
//ssyy добавил
if (((common_method_node)fn).is_constructor)
{
common_constructor_call ccc = new common_constructor_call((common_method_node)fn, loc);
//(ssyy) По-видимому, здесь всегда можно присваивать false, так как при создании нового объекта мы сюда не заходим...
ccc._new_obj_awaited = false;
if (!syntax_tree_visitor.context.allow_inherited_ctor_call)
{
throw new SimpleSemanticError(loc, "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST");
}
cmc = ccc;
}
else
//\ssyy
{
if (fn is generic_method_instance_node)
{
common_method_node cmn = (fn as generic_method_instance_node).original_function as common_method_node;
cmc = new common_method_call((common_method_node)fn, syntax_tree_visitor.GetCurrentObjectReference(cmn.cont_type.Scope, fn, loc), loc);
}
else
cmc = new common_method_call((common_method_node)fn, syntax_tree_visitor.GetCurrentObjectReference(((common_method_node)fn).cont_type.Scope, fn, loc), loc);
(cmc as common_method_call).virtual_call = !syntax_tree_visitor.inherited_ident_processing;
}
break;
}
case semantic_node_type.compiled_function_node:
{
cmc = new compiled_function_call((compiled_function_node)fn, syntax_tree_visitor.GetCurrentObjectReference(((compiled_function_node)fn).cont_type.Scope, fn, loc), loc);
(cmc as compiled_function_call).virtual_call = !syntax_tree_visitor.inherited_ident_processing;
break;
}
}
cmc.parameters.AddRange(exprs);
expr_node = cmc;
break;
}
case semantic_node_type.common_in_function_function_node:
{
common_in_function_function_node cffn = (common_in_function_function_node)fn;
common_in_function_function_call cffc = new common_in_function_function_call(cffn,
symtab.GetRelativeScopeDepth(cffn.function.scope, top_function.scope), loc);
cffc.parameters.AddRange(exprs);
expr_node = cffc;
break;
}
//ssyy добавил
case semantic_node_type.compiled_constructor_node:
{
compiled_constructor_node ccn = fn as compiled_constructor_node;
if (ccn == null)
{
throw new CompilerInternalError("compiled_constructor_node expected");
}
compiled_constructor_call ccc = new compiled_constructor_call(ccn, loc);
ccc.parameters.AddRange(exprs);
ccc._new_obj_awaited = false;
if (!syntax_tree_visitor.context.allow_inherited_ctor_call)
{
throw new SimpleSemanticError(loc, "INHERITED_CONSTRUCTOR_CALL_MUST_BE_FIRST");
}
expr_node = ccc;
break;
}
case semantic_node_type.indefinite_definition_node:
{
indefinite_function_call ifc = new indefinite_function_call(fn, loc);
ifc.parameters.AddRange(exprs);
expr_node = ifc;
break;
}
//\ssyy
default:
{
throw new NotSupportedError(loc);
}
}
return expr_node;
}
/// <summary>
/// Проверяет, что оператор статический метод класса.
/// </summary>
/// <param name="fn">Функция-оператор.</param>
public void check_operator(function_node fn)
{
switch (fn.semantic_node_type)
{
case semantic_node_type.common_in_function_function_node:
{
throw new CompilerInternalError("Operator can not be nested in function function.");
}
case semantic_node_type.common_method_node:
{
common_method_node cmn=(common_method_node)fn;
if (cmn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Operator can not be non static method");
}
break;
}
case semantic_node_type.compiled_function_node:
{
compiled_function_node cfn=(compiled_function_node)fn;
if (cfn.polymorphic_state!=SemanticTree.polymorphic_state.ps_static)
{
throw new CompilerInternalError("Operator can not be non static method. Included library is can be corrupted or library data extraction error.");
}
break;
}
}
}
/// <summary>
/// Создает узел преобразования типа, если необходимо.
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
/// <returns>Преобразованное выражение.</returns>
public expression_node convert_type(expression_node en, type_node to)
{
return convert_type(en, to, en.location);
}
/// <summary>
/// Проверяет можно ли неявно преобразовать. Если надо кидает исключение
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
public void check_convert_type(expression_node en, type_node to, location loc)
{
if (en.type == to)
return;
possible_type_convertions pct = type_table.get_convertions(en.type, to);
if (pct.second != null)
throw new TwoTypeConversionsPossible(en, pct.first, pct.second);
if (pct.first == null)
throw new CanNotConvertTypes(en, en.type, to, loc);
}
public bool can_convert_type(expression_node en, type_node to)
{
if (en.type == to)
return true;
possible_type_convertions pct = type_table.get_convertions(en.type, to);
if (pct.second != null)
return false;
if (pct.first == null)
return false;
return true;
}
public void check_convert_type_with_inheritance(type_node from, type_node to, location loc)
{
if (from == to)
return;
possible_type_convertions pct = type_table.get_convertions(from, to);
if (pct.second != null)
throw new TwoTypeConversionsPossibleT(pct.first, pct.second, loc);
if (pct.first == null && !type_table.is_derived(from, to))
throw new CanNotConvertTypes(null, from, to, loc);
}
/// <summary>
/// Создает узел преобразования типа, если необходимо.
/// </summary>
/// <param name="en">Выражение исходного типа.</param>
/// <param name="to">К какому типу нужно преобразовать.</param>
/// <param name="loc">Явный контекст.</param>
/// <returns>Преобразованное выражение.</returns>
public expression_node convert_type(expression_node en,type_node to, location loc)
{
if (en.type==to)
{
return en;
}
//TODO: А если наследование?
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)
{
en.location = loc;
throw new CanNotConvertTypes(en,en.type,to,loc);
}
#if (DEBUG)
check_operator(pct.first.convertion_method);
#endif
expression_node expr = create_simple_function_call(pct.first.convertion_method, en.location, en);
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;
/*if (to_type == SystemLibrary.SystemLibrary.object_type && from_type.is_value_type)
{
bfn = new basic_function_node(SemanticTree.basic_function_type.objtoobj, from_type, false);
with_compile_time_executor = false;
}
else*/
bfn = new basic_function_node(SemanticTree.basic_function_type.none, to_type, false);
bfn.parameters.AddElement(new basic_parameter("expr", from_type, SemanticTree.parameter_type.value, bfn));
if (with_compile_time_executor)
bfn.compile_time_executor = SystemLibrary.SystemLibrary.delegated_empty_method;
return bfn;
}
public expression_node explicit_convert_type(expression_node from, type_node to)
{
if (from.type == to)
{
return from;
}
possible_type_convertions ptc = type_table.get_convertions(from.type, to, false);
if (ptc.second != null)
{
AddError(new TwoTypeConversionsPossible(from, ptc.first, ptc.second));
}
if (ptc.first != null)
{
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;
return ret;
}
if ((type_table.is_derived(from.type, to)) || (type_table.is_derived(to, from.type)) || from.type.IsInterface || to.IsInterface)
{
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);
}
expression_node expr = create_simple_function_call(SystemLibrary.SystemLibrary.obj_to_obj, from.location, from);
//TODO: Переделать.
((base_function_call)expr).ret_type = to;
((base_function_call)expr).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,
parameter_list formalparams,bool is_alone_method_defined, location locg, out Errors.Error error)
{
//TODO:Явно указывать capacity при создании.
possible_type_convertions_list tc = new possible_type_convertions_list();
error = null;
possible_type_convertions ptc;
if (factparams.Count>formalparams.Count)
{
if ( (formalparams.Count==0) || (!(formalparams[formalparams.Count-1].is_params)) )
{
return null;
}
}
type_node for_par_type = null;
array_internal_interface aii=null;
if (formalparams.Count > 0)
{
parameter pr=formalparams[formalparams.Count - 1];
if (pr.is_params &&
//это для возможности вызова сразу с массивом[], типа просто не обращаем внимаение на params
!(factparams.Count == formalparams.Count && factparams[factparams.Count - 1].type == formalparams[formalparams.Count - 1].type))
{
//TODO: Добавить проверку на правильность.
aii = (array_internal_interface)
pr.type.get_internal_interface(internal_interface_kind.unsized_array_interface);
for_par_type = aii.element_type;
tc.snl = new statement_node_list();
location loc=null;
if (factparams.Count > 0) loc = factparams[factparams.Count-1].location;
//var_definition_node vdn=syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(),loc);
var_definition_node vdn = null;
if (syntax_tree_visitor.context.converted_func_stack.size > 0)
{
common_function_node cfn = syntax_tree_visitor.context.converted_func_stack.first();
if (cfn.is_generic_function)
{
vdn = syntax_tree_visitor.context.add_var_definition(get_temp_arr_name(), loc);
}
else if (syntax_tree_visitor.context.converted_type != null)
vdn = syntax_tree_visitor.context.add_field(get_temp_arr_name(), loc, pr.type, polymorphic_state.ps_static);
else
vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc);
}
else if (syntax_tree_visitor.context.converted_type != null)
vdn = syntax_tree_visitor.context.add_field(get_temp_arr_name(), loc, pr.type, polymorphic_state.ps_static);
else
vdn = syntax_tree_visitor.context.add_var_definition_in_entry_scope(get_temp_arr_name(), loc);
syntax_tree_visitor.context.close_var_definition_list(pr.type,null);
expression_node fst=null;
/*switch (syntax_tree_visitor.context.converting_block())
{
case block_type.function_block:
{
fst=new local_variable_reference((local_variable)vdn,0,loc);
break;
}
case block_type.namespace_block:
{
fst=new namespace_variable_reference((namespace_variable)vdn,loc);
break;
}
}*/
switch (vdn.semantic_node_type)
{
case semantic_node_type.local_variable:
{
fst = new local_variable_reference((local_variable)vdn, 0, loc);
break;
}
case semantic_node_type.namespace_variable:
{
fst = new namespace_variable_reference((namespace_variable)vdn, loc);
break;
}
case semantic_node_type.local_block_variable:
{
fst = new local_block_variable_reference((local_block_variable)vdn, loc);
break;
}
case semantic_node_type.class_field:
{
class_field cf = vdn as class_field;
cf.polymorphic_state = polymorphic_state.ps_static;
fst = new static_class_field_reference(cf, loc);
break;
}
default:
throw new CompilerInternalError("Invalid node type");
}
tc.var_ref = fst;
int del=factparams.Count-formalparams.Count+1;
int_const_node icn=new int_const_node(del,loc);
expression_node bfc = create_simple_function_call(SystemLibrary.SystemLibrary.resize_func,
loc, fst, icn);
tc.snl.AddElement(bfc);
/*if (factparams.Count == 0)
{
possible_type_convertions ptci=new possible_type_convertions();
ptci.first=null;
ptci.second=null;
ptci.from=null;
ptci.to = for_par_type;
tc.AddElement(ptci);
}*/
}
}
for(int i=0;i<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)
{
error = new CanNotConvertTypes(factparams[i], factparams[i].type, formal_param_type, locg);
//AddError(new CanNotConvertTypes(factparams[i], factparams[i].type, formal_param_type, locg));
}
return null;
}
}
else
{
tc.AddElement(ptc);
if ((for_par_type != null) && (i >= formalparams.Count - 1))
{
expression_node to = new simple_array_indexing(tc.var_ref,//factparams[formalparams.Count - 1],
new int_const_node(i - formalparams.Count + 1, factparams[i].location), aii.element_type, factparams[i].location);
expression_node from = create_simple_function_call(ptc.first.convertion_method,
factparams[i].location, factparams[i]);
statement_node stat = syntax_tree_visitor.find_operator(compiler_string_consts.assign_name, to, from, factparams[i].location);
tc.snl.AddElement(stat);
}
}
}
}
if (tc.snl != null)
foreach (statement_node sn in tc.snl)
sn.location = null;
return tc;
}
private simple_array_indexing make_unmanaged_string_getter(compiled_function_call cfc)
{
return new simple_array_indexing(cfc.obj, cfc.parameters[0], SystemLibrary.SystemLibrary.char_type, cfc.location);
}
private simple_array_indexing make_unmanaged_shortstring_getter(base_function_call cfc)
{
return new simple_array_indexing(cfc.parameters[0], cfc.parameters[1], SystemLibrary.SystemLibrary.char_type, cfc.location);
}
private bool is_string_getter(expression_node en)
{
if (en is common_namespace_function_call && (en as common_namespace_function_call).function_node == SystemLibrary.SystemLibInitializer.GetCharInShortStringProcedure.sym_info)
{
return true;
}
else if (en is compiled_static_method_call && (en as compiled_static_method_call).function_node == SystemLibrary.SystemLibInitializer.GetCharInShortStringProcedure.sym_info)
{
return true;
}
else if (en is compiled_function_call)
{
if ((en as compiled_function_call).function_node.cont_type != SystemLibrary.SystemLibrary.string_type)
return false;
if ((en as compiled_function_call).function_node.name.StartsWith("get_"))
return true;
}
return false;
}
private enum method_compare {less_method,greater_method,not_comparable_methods};
private enum type_conversion_compare {less_type_conversion,greater_type_conversion,equal_type_conversions};
private type_conversion_compare compare_type_conversions(possible_type_convertions left,possible_type_convertions right)
{
if ((left.first==null)&&(right.first!=null))
{
return type_conversion_compare.greater_type_conversion;
}
if ((left.first!=null)&&(right.first==null))
{
return type_conversion_compare.less_type_conversion;
}
if ((left.first != null) && (right.first != null))
{
convert_types_function_node cleft = left.first.convertion_method as convert_types_function_node;
convert_types_function_node cright = right.first.convertion_method as convert_types_function_node;
if ((cleft != null) && (cright != null))
{
if ((cleft.Good) && (!cright.Good))
{
return type_conversion_compare.greater_type_conversion;
}
if ((!cleft.Good) && (cright.Good))
{
return type_conversion_compare.less_type_conversion;
}
}
}
/*if ((left.first==null)&&(right.first==null))
{
return type_conversion_compare.equal_type_conversions;
}*/
//type_compare tc=type_table.compare_types(left.first.to,right.first.to);
type_compare tc=type_table.compare_types(left.to,right.to);
if (tc==type_compare.greater_type)
{
if (left.to.type_special_kind == type_special_kind.diap_type && left.to is common_type_node && right.to.type_special_kind == type_special_kind.diap_type && right.to is common_type_node)
{
tc = type_table.compare_types(left.to.base_type,right.to.base_type);
if (tc == type_compare.greater_type)
return type_conversion_compare.less_type_conversion;
}
else
return type_conversion_compare.less_type_conversion;
//return type_conversion_compare.greater_type_conversion;
}
if (tc==type_compare.less_type)
{
if (left.to.type_special_kind == type_special_kind.diap_type && left.to is common_type_node && right.to.type_special_kind == type_special_kind.diap_type && right.to is common_type_node)
{
tc = type_table.compare_types(left.to.base_type,right.to.base_type);
if (tc == type_compare.less_type)
return type_conversion_compare.greater_type_conversion;
}
else
return type_conversion_compare.greater_type_conversion;
//return type_conversion_compare.less_type_conversion;
}
internal_interface left_del = left.to.get_internal_interface(internal_interface_kind.delegate_interface);
internal_interface right_del = right.to.get_internal_interface(internal_interface_kind.delegate_interface);
if ((left_del == null) && (right_del == null))
{
return type_conversion_compare.equal_type_conversions;
}
if ((left_del == null) && (right_del != null))
{
return type_conversion_compare.less_type_conversion;
}
if ((left_del != null) && (right_del == null))
{
return type_conversion_compare.greater_type_conversion;
}
return type_conversion_compare.equal_type_conversions;
}
private method_compare compare_methods(function_node left_func, function_node right_func,
possible_type_convertions_list left,possible_type_convertions_list right)
{
function_compare fc = function_node.compare_functions(left_func, right_func);
if (fc == function_compare.less)
{
return method_compare.less_method;
}
if (fc == function_compare.greater)
{
return method_compare.greater_method;
}
bool left_greater=false;
bool right_greater=false;
for(int i=0;i<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)
{
return method_compare.greater_method;
}
if (left_func.is_generic_function_instance && !right_func.is_generic_function_instance)
{
return method_compare.less_method;
}
if (left_func.is_generic_function_instance && right_func.is_generic_function_instance)
{
if (left_func.generic_parameters_count > right_func.generic_parameters_count)
return method_compare.greater_method;
else if (left_func.generic_parameters_count < right_func.generic_parameters_count)
return method_compare.less_method;
else // SSM 8/8/15 Два метода одинаковы по всем параметрам, но у одного - больше instance_params, т.е. он менее специализирован
if (left_func.parameters.Count == right_func.parameters.Count)
{
bool eq = true;
for (var i=0; i<left_func.parameters.Count; i++)
if (left_func.parameters[i].type != right_func.parameters[i].type)
{
eq = false;
break;
}
if (eq)
{
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;
// Тут совпадать они не могут, но если совпадают - пусть уж будут несравнимыми
}
}
}
return method_compare.not_comparable_methods;
}
//DS добавил этот метод
//А так ли это надо делать?
//Сергей, может ты знаеш?
internal static bool eq_type_nodes(type_node tn1, type_node tn2, bool strong)
{
if (tn1 == tn2)
return true;
if (tn1 == null || tn2 == null)
{
return false;
}
if (tn1 is lambda_any_type_node || tn2 is lambda_any_type_node) //lroman// Считаем, что тип lambda_any_type_node равен всем типам. Это используется при выводе параметров лямбды
return true;
if (tn1.generic_function_container != null && tn2.generic_function_container != null)
{
if (strong && tn1.generic_function_container != tn2.generic_function_container)
{
return false;
}
return (tn1.generic_param_index == tn2.generic_param_index);
}
if (tn1.type_special_kind != tn2.type_special_kind)
{
return false;
}
switch (tn1.type_special_kind)
{
case type_special_kind.array_kind:
case type_special_kind.set_type:
case type_special_kind.typed_file:
if (tn1.type_special_kind == type_special_kind.array_kind)
{
if (tn1 is compiled_type_node && tn2 is compiled_type_node && (tn1 as compiled_type_node).rank != (tn2 as compiled_type_node).rank)
return false;
if (tn1 is common_type_node && tn2 is common_type_node && (tn1 as common_type_node).rank != (tn2 as common_type_node).rank)
return false;
}
return eq_type_nodes(tn1.element_type, tn2.element_type, strong);
}
ref_type_node rtn1 = tn1 as ref_type_node;
if (rtn1 != null)
{
ref_type_node rtn2 = tn2 as ref_type_node;
if (rtn2 == null)
{
return false;
}
return eq_type_nodes(rtn1.pointed_type, rtn2.pointed_type, strong);
}
if (tn1.is_generic_type_definition && tn2.is_generic_type_instance ||
tn2.is_generic_type_definition && tn1.is_generic_type_instance)
{
type_node tdef, tinst;
if (tn1.is_generic_type_definition)
{
tdef = tn1;
tinst = tn2;
}
else
{
tdef = tn2;
tinst = tn1;
}
if (tinst.original_generic != tdef)
{
return false;
}
if (tdef is common_type_node)
{
common_type_node ctdef = tdef as common_type_node;
int count = ctdef.generic_params.Count;
for (int i = 0; i < count; ++i)
{
if (ctdef.generic_params[i] != tinst.instance_params[i])
{
return false;
}
}
}
else if (tdef is compiled_type_node)
{
compiled_type_node ctdef = tdef as compiled_type_node;
int count = ctdef.generic_params.Count;
for (int i = 0; i < count; ++i)
{
if (ctdef.generic_params[i] != tinst.instance_params[i])
{
return false;
}
}
}
return true;
}
if (tn1.is_generic_type_instance)
{
if (!tn2.is_generic_type_instance)
{
return false;
}
if (tn1.original_generic != tn2.original_generic)
{
return false;
}
int count = tn1.instance_params.Count;
for (int i = 0; i < count; ++i)
{
if (!eq_type_nodes(tn1.instance_params[i], tn2.instance_params[i], strong))
{
return false;
}
}
return true;
}
if (tn1.get_internal_interface(internal_interface_kind.delegate_interface) != null)
{
delegate_internal_interface d1 = tn1.get_internal_interface(internal_interface_kind.delegate_interface) as delegate_internal_interface;
delegate_internal_interface d2 = tn2.get_internal_interface(internal_interface_kind.delegate_interface) as delegate_internal_interface;
if (d2 != null)
return function_eq_params_and_result(d1.invoke_method, d2.invoke_method);
}
return false;
}
internal static bool eq_type_nodes(type_node tn1, type_node tn2)
{
return eq_type_nodes(tn1, tn2, false);
}
//Этот метод сверяет не только параметры, но и возвращаемое значение
public static bool function_eq_params_and_result(function_node left, function_node right, bool weak=false)
{
if (!function_eq_params(left, right, weak))
{
return false;
}
else
{
return eq_type_nodes(left.return_value_type,right.return_value_type);
}
}
//Сравниваем типы-параметры generic-функций
public static bool function_eq_generic_params(function_node left, function_node right)
{
List<type_node> left_type_params = left.get_generic_params_list();
List<type_node> right_type_params = right.get_generic_params_list();
if (left_type_params == null && right_type_params == null)
{
return true;
}
if (left_type_params == null || right_type_params == null)
{
return false;
}
if (left_type_params.Count != right_type_params.Count)
{
return false;
}
for (int i = 0; i < left_type_params.Count; i++)
{
if (string.Compare(left_type_params[i].name, right_type_params[i].name, true) != 0)
{
return false;
}
}
return true;
}
public static bool function_eq_params(function_node left, function_node right)
{
return function_eq_params(left, right, true);
}
public static bool function_eq_params(function_node left, function_node right, bool compare_parameter_types)
{
if (compare_parameter_types)
{
if (!function_eq_generic_params(left, right))
{
return false;
}
}
else
{
if (left.generic_parameters_count != right.generic_parameters_count)
{
return false;
}
}
if (left.parameters.Count != right.parameters.Count)
{
return false;
}
for (int i = 0; i < left.parameters.Count; i++)
{
if (!eq_type_nodes(left.parameters[i].type,right.parameters[i].type) ||
compare_parameter_types && left.parameters[i].parameter_type != right.parameters[i].parameter_type)
{
return false;
}
}
return true;
}
private void check_single_possible_convertion(ILocation loc,possible_type_convertions_list ptcal)
{
foreach(possible_type_convertions ptc in ptcal)
{
if (ptc.second!=null)
{
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))
{
if (exprs.Count == 0 && fn.parameters != null && fn.parameters.Count == 1 && fn.parameters[0].is_params ||
exprs.Count == 1 && fn.parameters != null && fn is common_namespace_function_node && (fn as common_namespace_function_node).ConnectedToType != null &&
fn.parameters.Count == 2 && fn.parameters[1].is_params)
{
statements_expression_node sre = new statements_expression_node(ptcal.snl, ptcal.var_ref, ptcal.var_ref.location);
//exprs.remove_range(fn.parameters.Count - 1, exprs.Count - fn.parameters.Count);
//exprs.AddElement(ptcal.var_ref);
//exprs[i] = ptcal.var_ref;
exprs.AddElement(sre);
}
common_function_node cfn = (common_function_node)fn;
for (int j = exprs.Count; j < cfn.parameters.Count; j++)
{
common_parameter cp = (common_parameter)cfn.parameters[j];
if (cp.default_value != null)
exprs.AddElement(cp.default_value);
}
}
else if ((exprs.Count < fn.parameters.Count) && (fn.node_kind == SemanticTree.node_kind.compiled))
{
if (exprs.Count == 0 && fn.parameters != null && fn.parameters.Count == 1 && fn.parameters[0].is_params ||
exprs.Count == 1 && fn.parameters != null && fn is compiled_function_node && (fn as compiled_function_node).ConnectedToType != null &&
fn.parameters.Count == 2 && fn.parameters[1].is_params)
{
statements_expression_node sre = new statements_expression_node(ptcal.snl, ptcal.var_ref, ptcal.var_ref.location);
exprs.AddElement(sre);
}
//compiled_function_node cfn = (compiled_function_node)fn;
for (int j = exprs.Count; j < fn.parameters.Count; j++)
{
compiled_parameter cp = (compiled_parameter)fn.parameters[j];
if (cp.default_value != null)
exprs.AddElement(cp.default_value);
}
}
}
private function_node find_eq_return_value_method_in_list(function_node fn, function_node_list funcs)
{
foreach (function_node f in funcs)
{
//Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть.
if (f == fn)
{
return f;
}
if (function_eq_params_and_result(fn,f))
{
if (fn.original_function == f.original_function)
{
return f;
}
}
}
return null;
}
public function_node find_eq_method_in_list(function_node fn,function_node_list funcs)
{
foreach(function_node f in funcs)
{
//Проверка добавлена 14.07.2006 в 14.28. Нужно с ней прогнать тесты, хотя вроде вреда от нее не должно быть.
if (f==fn)
{
return f;
}
if (function_eq_params(fn, f))
{
if (fn.original_function == f.original_function)
{
return f;
}
}
}
return null;
}
public function_node is_exist_eq_method_in_list(function_node fn, function_node_list funcs)
{
return find_eq_return_value_method_in_list(fn, funcs);
}
public void init_reference_type(type_node ctn)
{
SystemLibrary.SystemLibrary.init_reference_type(ctn);
}
//Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов.
public function_node select_function(expressions_list parameters, SymbolInfo functions, location loc, List<SyntaxTree.expression> syntax_nodes_parameters = null)
{
if (functions==null)
{
return AddError<function_node>(new NoFunctionWithThisName(loc));
}
function_node_list set_of_possible_functions = new function_node_list();
bool is_alone_method_defined = (functions.Next == null);
function_node first_function = functions.sym_info as function_node;
bool _is_assigment = first_function.name == compiler_string_consts.assign_name;
basic_function_node _tmp_bfn = functions.sym_info as basic_function_node;
List<function_node> indefinits = new List<function_node>();
while(functions!=null)
{
#if (DEBUG)
if (functions.sym_info.general_node_type!=general_node_type.function_node && functions.sym_info.general_node_type != general_node_type.property_node)
{
throw new CompilerInternalError("Function name is used to define another kind of object.");
}
#endif
function_node fn = null;
if (functions.sym_info.general_node_type == general_node_type.property_node)
{
fn = (functions.sym_info as property_node).get_function;
}
else
fn=(function_node)functions.sym_info;
if (fn.node_kind == node_kind.indefinite)
{
indefinits.Add(fn);
}
else if (fn.node_kind==SemanticTree.node_kind.common)
{
common_function_node cfn=(common_function_node)fn;
if ((parameters.Count>=cfn.parameters.Count-cfn.num_of_default_variables)&&
(parameters.Count<=cfn.parameters.Count) || parameters.Count == 0 && cfn.parameters.Count == 1 && cfn.parameters[0].is_params)
{
if (is_exist_eq_method_in_list(fn,set_of_possible_functions) != null)
{
//!!!!!!!!!!!!!
//DS TODO
//Это нужно чтобы была возможность создавать операторы = := ..., т.к. всегда они добавляюся автоматом
//Надо сначало просматривать заголовки и добавлять такие операторы только если нужно.
if (set_of_possible_functions.Count > 0)
if (set_of_possible_functions[0] is basic_function_node)
{
set_of_possible_functions.remove(set_of_possible_functions[0]);
set_of_possible_functions.AddElement(fn);
}
//!!!!!!!!!!!!!
functions=functions.Next;
continue;
}
set_of_possible_functions.AddElement(fn);
}
}
else
{
//TODO: Здесь нужно поправить, если создавать возможность вызова метода с параметрами по умолчанию из откомпилированной dll.
if (parameters.Count==fn.parameters.Count)
{
function_node func = null;
if ((func=is_exist_eq_method_in_list(fn,set_of_possible_functions)) != null)
{
if (!eq_type_nodes(fn.return_value_type, func.return_value_type))
{
set_of_possible_functions[set_of_possible_functions.IndexOf(func)] = fn;
}
functions = functions.Next;
continue;
}
set_of_possible_functions.AddElement(fn);
}
}
if (parameters.Count > fn.parameters.Count)
{
if (fn.parameters.Count > 0)
{
if ((fn.parameters[fn.parameters.Count - 1]).is_params)
{
//+DS ms0105
if (is_exist_eq_method_in_list(fn, set_of_possible_functions) != null)
{
functions = functions.Next;
continue;
}
//-DS
set_of_possible_functions.AddElement(fn);
}
}
}
else if ((parameters.Count == 0 && fn.parameters.Count == 1) && fn.parameters[0].is_params && !set_of_possible_functions.Contains(fn))
set_of_possible_functions.AddElement(fn);
else if (fn.num_of_default_parameters != 0 && parameters.Count >= fn.parameters.Count - fn.num_of_default_parameters)
{
if (!set_of_possible_functions.Contains(fn))
set_of_possible_functions.AddElement(fn);
}
else if (parameters.Count == 1 && fn is common_namespace_function_node && (fn as common_namespace_function_node).ConnectedToType != null && fn.parameters.Count == 2 && fn.parameters[1].is_params)
set_of_possible_functions.AddElement(fn);
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);
functions =functions.Next;
}
if (set_of_possible_functions.Count==0 && indefinits.Count == 0)
{
return AddError<function_node>(new NoFunctionWithSameParametresNum(loc, is_alone_method_defined, first_function));
}
//(ssyy) Инициализируем is_alone_defined
FailedWhileTryingToCompileLambdaBodyWithGivenParametersException lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = null;
if (set_of_possible_functions.Count == 1 && indefinits.Count == 0)
{
is_alone_method_defined = true;
}
//(ssyy) Инстанцируем дженерики
for (int i = set_of_possible_functions.Count - 1; i > -1; --i)
{
function_node func = set_of_possible_functions[i];
if (func.is_generic_function)
{
try
{
function_node inst = generic_convertions.DeduceFunction(func, parameters,
is_alone_method_defined, loc, syntax_nodes_parameters);
if (inst == null)
{
set_of_possible_functions.remove_at(i);
}
else
{
set_of_possible_functions[i] = inst;
}
}
catch (FailedWhileTryingToCompileLambdaBodyWithGivenParametersException exc) //lroman Отлавливаем последнее исключение, которое возникло при попытке скомпилировать тело лямбды с заданными типами параметров
{
set_of_possible_functions.remove_at(i);
lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException = exc;
}
}
}
if (lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException != null
&& set_of_possible_functions.Count == 0
&& indefinits.Count == 0)
{
throw lastFailedWhileTryingToCompileLambdaBodyWithGivenParametersException.ExceptionOnCompileBody; // Если перебрали все, но ничто не подошло, то кидаем последнее исключение
}
if (set_of_possible_functions.Count == 0 && indefinits.Count == 0)
{
return AddError<function_node>(loc, "CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS", first_function.name);
}
possible_type_convertions_list_list tcll = new possible_type_convertions_list_list();
for (int i = 0; i < set_of_possible_functions.Count; i++)
{
Errors.Error err = null;
possible_type_convertions_list tc = get_conversions(parameters, set_of_possible_functions[i].parameters,
is_alone_method_defined, loc, out err);
if (err != null)
return AddError<function_node>(err);
//fix dlja lambd i extension metodov (c->c.IsDigit)
if (tc == null)
{
expressions_list el = new expressions_list();
el.AddRange(parameters);
bool has_lambda_var = false;
for (int k = 0; k < el.Count; k++)
{
if (el[k] is local_variable_reference && el[k].type is delegated_methods && (el[k].type as delegated_methods).empty_param_method != null)
{
el[k].type = (el[k].type as delegated_methods).empty_param_method.ret_type;
has_lambda_var = true;
}
}
if (has_lambda_var)
{
err = null;
tc = get_conversions(el, set_of_possible_functions[i].parameters,
is_alone_method_defined, loc, out err);
if (err != null)
return AddError<function_node>(err);
}
}
tcll.AddElement(tc);
}
int j=0;
while(j<set_of_possible_functions.Count)
{
if (tcll[j]==null && set_of_possible_functions[j].node_kind != node_kind.indefinite)
{
tcll.remove_at(j);
set_of_possible_functions.remove_at(j);
}
else
{
j++;
}
}
if (set_of_possible_functions.Count==0 && indefinits.Count == 0)
{
if (_is_assigment && parameters.Count == 2)
return AddError<function_node>(new CanNotConvertTypes(parameters[1], parameters[1].type, parameters[0].type, parameters[1].location));
if (_tmp_bfn != null && parameters.Count == 2)
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));
}
bool remove=true;
while(remove)
{
if (set_of_possible_functions.Count==1)
{
check_single_possible_convertion(loc,tcll[0]);
convert_function_call_expressions(set_of_possible_functions[0],parameters,tcll[0]);
return set_of_possible_functions[0];
}
remove=false;
var i = 0;
while (i < set_of_possible_functions.Count-1)
{
j = i+1;
while (j < set_of_possible_functions.Count)
{
method_compare mc = compare_methods(set_of_possible_functions[i],
set_of_possible_functions[j], tcll[i], tcll[j]);
if (SystemLibrary.SystemLibInitializer.InSetProcedure != null)
{
if (set_of_possible_functions[j] == SystemLibrary.SystemLibInitializer.InSetProcedure.sym_info)
{
mc = method_compare.less_method;
}
else if (set_of_possible_functions[i] == SystemLibrary.SystemLibInitializer.InSetProcedure.sym_info)
{
mc = method_compare.greater_method;
}
}
if (mc == method_compare.greater_method)
{
tcll.remove_at(j);
set_of_possible_functions.remove_at(j);
remove = true;
}
else if (mc == method_compare.less_method)
{
tcll[i] = tcll[j];
set_of_possible_functions[i] = set_of_possible_functions[j];
tcll.remove_at(j);
set_of_possible_functions.remove_at(j);
remove = true;
}
else
{
j++;
}
}
i++;
}
}
//Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений
//в дальнейшем может вызвать странное поведение, это надо проверить
if (set_of_possible_functions.Count == 2 && indefinits.Count == 0)
if (set_of_possible_functions[0] is basic_function_node && set_of_possible_functions[1] is basic_function_node)
return set_of_possible_functions[0];
if (indefinits.Count > 0)
{
if (indefinits.Count == 1 && set_of_possible_functions.Count == 0)
{
return indefinits[0];
}
indefinits.AddRange(set_of_possible_functions);
return new indefinite_functions_set(indefinits);
}
bool exist_indefinite_parameter = false;
foreach (expression_node par in parameters)
{
if (par.type.depended_from_indefinite)
{
exist_indefinite_parameter = true;
break;
}
}
if (exist_indefinite_parameter)
{
indefinits.AddRange(set_of_possible_functions);
return new indefinite_functions_set(indefinits);
}
SortedDictionary<int, List<function_node>> distances = new SortedDictionary<int, List<function_node>>();
function_node best_function = null;
List<function_node> to_remove = new List<function_node>();
foreach (function_node fn in set_of_possible_functions)
{
if (fn.return_value_type != null)
{
if (best_function == null)
{
best_function = fn;
}
else
{
type_compare tc = type_table.compare_types(best_function.return_value_type, fn.return_value_type);
if (tc == type_compare.greater_type)
{
to_remove.Add(best_function);
best_function = fn;
}
else if (tc == type_compare.less_type)
to_remove.Add(fn);
}
}
}
foreach (function_node fn in to_remove)
{
set_of_possible_functions.remove(fn);
}
foreach (function_node fn in set_of_possible_functions)
{
int distance = 0;
for (int i = 0; i < parameters.Count; i++)
{
type_node from = parameters[i].type;
type_node to = fn.parameters[Math.Min(i,fn.parameters.Count-1)].type;
if (fn.parameters[Math.Min(i, fn.parameters.Count - 1)].is_params)
to = to.element_type;
distance += get_type_distance(from, to);
}
/*if (fn.return_value_type != null)
{
if (fn.return_value_type.is_generic_type_instance || fn.return_value_type.is_generic_type_definition)
distance += 2;
else if (fn.return_value_type == SystemLibrary.SystemLibrary.object_type)
distance += 3;
else
distance += 1;
}*/
List<function_node> lst;
if (distances.TryGetValue(distance,out lst))
{
lst.Add(fn);
}
else
{
lst = new List<function_node>();
lst.Add(fn);
distances[distance] = lst;
}
}
foreach (int dist in distances.Keys)
{
List<function_node> funcs = distances[dist];
if (funcs.Count == 1)
{
Errors.Error err = null;
possible_type_convertions_list tcl = get_conversions(parameters, funcs[0].parameters, true, loc, out err);
if (err != null)
return AddError<function_node>(err);
convert_function_call_expressions(funcs[0], parameters, tcl);
return funcs[0];
}
}
return AddError<function_node>(new SeveralFunctionsCanBeCalled(loc,set_of_possible_functions));
}
private int get_type_distance(type_node from, type_node to)
{
if (from == to)
return 0;
type_compare tc = type_table.compare_types(from, to);
if (tc == type_compare.non_comparable_type)
return 1000;
if (!from.IsInterface && to.IsInterface)
return 2;
if (tc == type_compare.less_type)
return 1;
if (tc == type_compare.greater_type)
return 3;
return 1000;
}
private function_node is_exist_eq_return_value_method(function_node fn, function_node_list funcs)
{
fn = find_eq_return_value_method_in_list(fn, funcs);
return fn;
}
private string get_return_variable_name(string function_name)
{
return (compiler_string_consts.function_return_value_prefix+function_name);
}
public void create_function_return_variable(common_function_node cfn, SymbolInfo ret_var)
{
if (!SemanticRules.AddResultVariable)
return;
//#if (DEBUG)
if (cfn.return_value_type==null)
{
return;
//throw new CompilerInternalError("Procedure can not return value");
}
//#endif
if (cfn.return_variable != null)
{
if (ret_var != null)
ret_var.sym_info = cfn.return_variable;
return;
}
cfn.return_variable=new local_variable(get_return_variable_name(cfn.name),cfn.return_value_type,cfn,cfn.loc);
cfn.return_variable.inital_value = syntax_tree_visitor.context.GetInitalValueForVariable(cfn.return_variable,null);
cfn.var_definition_nodes_list.AddElement(cfn.return_variable);
if (ret_var != null)
{
ret_var.sym_info = cfn.return_variable;
}
}
public void check_node_parser_error(SyntaxTree.syntax_tree_node tn)
{
if (_parser_error == null || tn==null)
{
return;
}
if (bad_nodes_in_syntax_tree[tn]!=null)
{
AddError(new ParserError(_parser_error,_stv.get_location(tn)));
}
}
public type_node select_base_type(type_node_list types)
{
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;
}
}
}