2018-05-01 19:29:39 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2018-05-09 15:31:50 +03:00
|
|
|
|
using System.Diagnostics;
|
2018-05-01 19:29:39 +03:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2018-05-06 20:09:36 +03:00
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
2018-05-01 19:29:39 +03:00
|
|
|
|
using PascalABCCompiler.TreeRealization;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PascalABCCompiler.TreeConverter
|
|
|
|
|
|
{
|
2018-05-11 13:46:59 +03:00
|
|
|
|
// Patterns
|
2018-05-01 19:29:39 +03:00
|
|
|
|
public partial class syntax_tree_visitor
|
|
|
|
|
|
{
|
2018-05-06 20:09:36 +03:00
|
|
|
|
public override void visit(desugared_deconstruction deconstruction)
|
|
|
|
|
|
{
|
|
|
|
|
|
var invokationTarget = convert_strong(deconstruction.deconstruction_target as expression);
|
2018-05-09 15:31:50 +03:00
|
|
|
|
var types = InferAndCheckPatternVariableTypes(deconstruction.definitions, invokationTarget, deconstruction);
|
2018-05-06 20:09:36 +03:00
|
|
|
|
if (types == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var definition in deconstruction.WithTypes(types.Select(x => new semantic_type_node(x)).ToArray()))
|
|
|
|
|
|
definition.visit(this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
private type_node[] InferAndCheckPatternVariableTypes(List<var_def_statement> variableDefinitions, expression_node patternInstance, desugared_deconstruction deconstruction)
|
2018-05-06 20:09:36 +03:00
|
|
|
|
{
|
2018-05-09 15:31:50 +03:00
|
|
|
|
var parameterTypes = variableDefinitions.Select(x => x.vars_type == null ? null : convert_strong(x.vars_type)).ToArray();
|
|
|
|
|
|
List<function_node> candidates = new List<function_node>();
|
2018-05-09 23:56:49 +03:00
|
|
|
|
List<type_node[]> deducedParametersList = new List<type_node[]>();
|
2018-05-09 15:31:50 +03:00
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
var allDeconstructs = patternInstance.type.find_in_type("deconstruct", context.CurrentScope);
|
2018-05-11 14:11:56 +03:00
|
|
|
|
foreach (var canditateSymbol in allDeconstructs)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
var deducedParameters = new type_node[parameterTypes.Length];
|
2018-05-09 15:31:50 +03:00
|
|
|
|
var possibleCandidate = canditateSymbol.sym_info as function_node;
|
2018-05-09 23:56:49 +03:00
|
|
|
|
if (!IsSuitableFunction(possibleCandidate, parameterTypes, patternInstance, get_location(deconstruction), out deducedParameters))
|
2018-05-09 15:31:50 +03:00
|
|
|
|
continue;
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
deducedParametersList.Add(deducedParameters);
|
2018-05-09 15:31:50 +03:00
|
|
|
|
candidates.Add(possibleCandidate);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (candidates.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddError(get_location(deconstruction), "NO_SUITABLE_DECONSTRUCT_FOUND");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
if (candidates.Count > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
RemoveDefaultDeconstruct(candidates);
|
2018-05-09 23:56:49 +03:00
|
|
|
|
if (candidates.Count > 1 && !CheckIfParameterListElementsAreTheSame(deducedParametersList))
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
|
|
|
|
|
AddError(get_location(deconstruction), "DECONSTRUCTOR_METHOD_AMBIGUITY");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
// Единственный подхдящий кандидат найден, либо их несколько, с одинаковыми выходными параметрами
|
|
|
|
|
|
var chosenFunction = candidates.First();
|
|
|
|
|
|
if (chosenFunction.is_extension_method)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
if (chosenFunction.is_generic_function)
|
|
|
|
|
|
chosenFunction = generic_convertions.get_function_instance(chosenFunction, deducedParametersList.First().ToList());
|
2018-05-09 15:31:50 +03:00
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
return chosenFunction.parameters.Where(x => !IsSelfParameter(x)).Select(x => x.type).ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return chosenFunction.parameters.Select(x => x.type).ToArray();//deducedParametersList[0];
|
2018-05-09 15:31:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Проверяет, подходит ли фаункция для вызова с указанными параметрами
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="candidate"></param>
|
2018-05-09 23:56:49 +03:00
|
|
|
|
/// <param name="givenParameterTypes">Типы параметров, указанные пользователем</param>
|
2018-05-09 15:31:50 +03:00
|
|
|
|
/// <returns></returns>
|
2018-05-09 23:56:49 +03:00
|
|
|
|
private bool IsSuitableFunction(
|
|
|
|
|
|
function_node candidate,
|
|
|
|
|
|
type_node[] givenParameterTypes,
|
|
|
|
|
|
expression_node patternInstance,
|
|
|
|
|
|
location deconstructionLocation,
|
|
|
|
|
|
out type_node[] parameterTypes)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
parameterTypes = new type_node[givenParameterTypes.Length];
|
|
|
|
|
|
var selfParameter = candidate.is_extension_method ? candidate.parameters.First(IsSelfParameter) : null;
|
2018-05-11 19:26:55 +03:00
|
|
|
|
Debug.Assert(!candidate.is_extension_method || selfParameter != null, "Couldn't find self parameter in extension method");
|
2018-05-09 15:31:50 +03:00
|
|
|
|
var candidateParameterTypes =
|
|
|
|
|
|
candidate.is_extension_method ?
|
|
|
|
|
|
candidate.parameters.Where(x => !IsSelfParameter(x)).ToArray() :
|
|
|
|
|
|
candidate.parameters.ToArray();
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
if (candidateParameterTypes.Length != givenParameterTypes.Length)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
var genericDeduceNeeded = candidate.is_extension_method && candidate.is_generic_function;
|
|
|
|
|
|
type_node[] deducedGenerics = new type_node[candidate.generic_parameters_count];
|
|
|
|
|
|
if (genericDeduceNeeded)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Выводим дженерики по self
|
|
|
|
|
|
var nils = new List<int>();
|
|
|
|
|
|
var deduceSucceded = generic_convertions.DeduceInstanceTypes(selfParameter.type, patternInstance.type, deducedGenerics, nils);
|
|
|
|
|
|
if (!deduceSucceded || deducedGenerics.Contains(null))
|
2018-05-11 19:26:55 +03:00
|
|
|
|
// Проверка на то, что в Deconstruct все дженерики выводятся по self делается в другом месте
|
|
|
|
|
|
// TODO: сделать проверку
|
|
|
|
|
|
// TODO: запретить дженерик методы в классах. Можно использовать только дженерик-типы самого класса в качестве параметров
|
|
|
|
|
|
//AddError(deconstructionLocation, "COULDNT_DEDUCE_DECONSTRUCT_GENERIC_TYPE");
|
2018-05-09 23:56:49 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < givenParameterTypes.Length; i++)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
var givenParameter = givenParameterTypes[i];
|
|
|
|
|
|
var candidateParameter = candidateParameterTypes[i].type;
|
|
|
|
|
|
if (genericDeduceNeeded && (candidateParameter.is_generic_parameter || candidateParameter.is_generic_type_instance))
|
2018-05-11 19:26:55 +03:00
|
|
|
|
candidateParameter = InstantiateParameter(candidateParameter, deducedGenerics);
|
2018-05-09 23:56:49 +03:00
|
|
|
|
|
|
|
|
|
|
if (givenParameter != null && !AreTheSameTypes(candidateParameter, givenParameter))
|
2018-05-09 15:31:50 +03:00
|
|
|
|
return false;
|
2018-05-09 23:56:49 +03:00
|
|
|
|
|
|
|
|
|
|
parameterTypes[i] = candidateParameter;
|
2018-05-09 15:31:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool AreTheSameTypes(type_node type1, type_node type2)
|
|
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
return convertion_data_and_alghoritms.possible_equal_types(type1, type2);
|
2018-05-09 15:31:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsSelfParameter(parameter parameter) => parameter.name.ToLower() == compiler_string_consts.self_word;
|
|
|
|
|
|
|
|
|
|
|
|
private void RemoveDefaultDeconstruct(List<function_node> candidates)
|
|
|
|
|
|
{
|
|
|
|
|
|
var index = candidates.FindIndex(IsDefaultDeconstruct);
|
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
|
candidates.RemoveAt(index);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
private bool IsDefaultDeconstruct(function_node function)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
// TODO: fix
|
2018-05-09 15:31:50 +03:00
|
|
|
|
return
|
|
|
|
|
|
function.generic_parameters_count == 1 &&
|
|
|
|
|
|
function.parameters.Count == 2 &&
|
|
|
|
|
|
function.parameters[0].type.is_generic_parameter &&
|
|
|
|
|
|
function.parameters[1].type.is_generic_parameter &&
|
|
|
|
|
|
AreTheSameTypes(function.parameters[0].type, function.parameters[1].type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-09 23:56:49 +03:00
|
|
|
|
private bool CheckIfParameterListElementsAreTheSame(List<type_node[]> parametersList)
|
2018-05-09 15:31:50 +03:00
|
|
|
|
{
|
2018-05-09 23:56:49 +03:00
|
|
|
|
var first = parametersList.First();
|
|
|
|
|
|
for (int i = 1; i < parametersList.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (first.Length != parametersList[i].Length)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < first.Length; j++)
|
|
|
|
|
|
if (!AreTheSameTypes(first[j], parametersList[i][j]))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private type_node InstantiateParameter(SemanticTree.ITypeNode genericType, type_node[] instances)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (genericType.is_generic_parameter)
|
|
|
|
|
|
return instances[(genericType as type_node).generic_param_index];
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var genericNode = (genericType as generic_instance_type_node);
|
|
|
|
|
|
if (genericNode != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var parameters = genericNode.instance_params.Select(x => InstantiateParameter(x, instances)).ToList();
|
|
|
|
|
|
genericNode.instance_params = parameters;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return genericNode as type_node;
|
|
|
|
|
|
}
|
2018-05-06 20:09:36 +03:00
|
|
|
|
}
|
2018-05-01 19:29:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|