2017-02-20 13:57:13 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
|
|
|
|
|
using PascalABCCompiler.TreeConversion;
|
2018-05-13 20:49:08 +03:00
|
|
|
|
using PascalABCCompiler.TreeConverter;
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
|
|
|
|
|
namespace SyntaxVisitors.SugarVisitors
|
|
|
|
|
|
{
|
2018-05-11 13:46:59 +03:00
|
|
|
|
// Patterns
|
|
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
public class DeconstructionDesugaringResult
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Переменная, имеющая тип паттерна
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public var_statement CastVariableDefinition { get; set; }
|
|
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Переменная, в которую сохраняется результат мэтчинга
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public var_statement SuccessVariableDefinition { get; set; }
|
|
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Переменные, полученные в результате деконструкции
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<var_def_statement> DeconstructionVariables { get; private set; } = new List<var_def_statement>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Проверка соответствия типа выражения типу паттерна
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public expression TypeCastCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Вызов Deconstruct
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public statement DeconstructCall { get; set; }
|
|
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
public ident CastVariable => CastVariableDefinition.var_def.vars.list.First();
|
|
|
|
|
|
|
|
|
|
|
|
public ident SuccessVariable => SuccessVariableDefinition.var_def.vars.list.First();
|
|
|
|
|
|
|
|
|
|
|
|
public List<statement> GetDeconstructionDefinitions(SourceContext patternContext)
|
2018-05-06 20:09:36 +03:00
|
|
|
|
{
|
2018-05-16 00:26:07 +03:00
|
|
|
|
var result = new List<statement>();
|
|
|
|
|
|
result.Add(CastVariableDefinition);
|
2019-05-24 10:04:17 +03:00
|
|
|
|
result.Add(new desugared_deconstruction(DeconstructionVariables, CastVariable, patternContext));
|
2018-05-15 17:55:57 +03:00
|
|
|
|
result.Add(SuccessVariableDefinition);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public if_node GetPatternCheckWithDeconstrunctorCall()
|
|
|
|
|
|
{
|
|
|
|
|
|
return SubtreeCreator.CreateIf(
|
|
|
|
|
|
TypeCastCheck,
|
|
|
|
|
|
new statement_list(new assign(SuccessVariable.name, true), DeconstructCall));
|
2018-05-06 20:09:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
public class CollectionDesugaringResult
|
|
|
|
|
|
{
|
|
|
|
|
|
public List<statement> VarParametersDeclarations { get; set; } = new List<statement>();
|
|
|
|
|
|
|
|
|
|
|
|
public expression SuccessMatchingCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public expression CollectionLengthCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public List<semantic_check_sugared_statement_node> ElemTypeChecks { get; set; } = new List<semantic_check_sugared_statement_node>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class TupleDesugaringResult
|
|
|
|
|
|
{
|
|
|
|
|
|
public List<statement> VarParametersDeclarations { get; set; } = new List<statement>();
|
|
|
|
|
|
|
|
|
|
|
|
public expression SuccessMatchingCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public statement TupleLengthCheck { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public List<semantic_check_sugared_statement_node> ElemTypeChecks { get; set; } = new List<semantic_check_sugared_statement_node>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-13 20:49:08 +03:00
|
|
|
|
public class PatternsDesugaringVisitor : BaseChangeVisitor
|
2017-02-20 13:57:13 +03:00
|
|
|
|
{
|
2018-05-15 17:55:57 +03:00
|
|
|
|
private enum PatternLocation { Unknown, IfCondition, Assign }
|
|
|
|
|
|
|
2018-05-13 20:49:08 +03:00
|
|
|
|
private const string DeconstructMethodName = compiler_string_consts.deconstruct_method_name;
|
2018-05-15 17:55:57 +03:00
|
|
|
|
private const string IsTestMethodName = compiler_string_consts.is_test_function_name;
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private const string WildCardsTupleEqualFunctionName = compiler_string_consts.wild_cards_tuple_equal_function_name;
|
|
|
|
|
|
private const string SeqFunctionName = compiler_string_consts.seq_function_name;
|
|
|
|
|
|
private const string CountPropertyName = compiler_string_consts.count_property_name;
|
2018-05-15 17:55:57 +03:00
|
|
|
|
private const string GeneratedPatternNamePrefix = "<>pattern";
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private const string GeneratedDeconstructParamPrefix = "<>deconstructParam";
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
2018-05-17 22:49:07 +03:00
|
|
|
|
private int generalVariableCounter = 0;
|
|
|
|
|
|
private int successVariableCounter = 0;
|
|
|
|
|
|
private int labelVariableCounter = 0;
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private int deconstructParamVariableCounter = 0;
|
2018-05-17 22:49:07 +03:00
|
|
|
|
|
2017-12-11 19:26:57 +03:00
|
|
|
|
private if_node _previousIf;
|
2018-05-11 19:26:55 +03:00
|
|
|
|
private statement desugaredMatchWith;
|
2018-05-16 00:26:07 +03:00
|
|
|
|
private List<if_node> processedIfNodes = new List<if_node>();
|
|
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
//const matching
|
|
|
|
|
|
private List<statement> typeChecks = new List<statement>();
|
|
|
|
|
|
|
2018-05-13 20:49:08 +03:00
|
|
|
|
public static PatternsDesugaringVisitor New => new PatternsDesugaringVisitor();
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
|
|
|
|
|
public override void visit(match_with matchWith)
|
|
|
|
|
|
{
|
2017-12-11 19:26:57 +03:00
|
|
|
|
desugaredMatchWith = null;
|
|
|
|
|
|
_previousIf = null;
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
2018-05-17 23:49:50 +03:00
|
|
|
|
// Кэшируем выражение для однократного вычисления
|
2018-05-18 21:25:37 +03:00
|
|
|
|
//var cachedExpression = NewGeneralName();
|
|
|
|
|
|
//AddDefinitionsInUpperStatementList(matchWith, new[] { new var_statement(cachedExpression, matchWith.expr) });
|
2018-05-17 23:49:50 +03:00
|
|
|
|
|
2017-03-06 02:00:50 +03:00
|
|
|
|
// Преобразование из сахара в известную конструкцию каждого case
|
2018-12-13 11:11:07 +03:00
|
|
|
|
var usedDeconstructionTypes = new HashSet<string>();
|
2017-02-20 13:57:13 +03:00
|
|
|
|
foreach (var patternCase in matchWith.case_list.elements)
|
|
|
|
|
|
{
|
2018-05-11 13:46:59 +03:00
|
|
|
|
if (patternCase == null)
|
|
|
|
|
|
continue;
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
switch (patternCase.pattern)
|
2018-12-13 11:11:07 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
case deconstructor_pattern pattern:
|
2018-12-13 11:11:07 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
// Проверяем встречался ли уже такой тип при деконструкции
|
|
|
|
|
|
// SSM 02.01.19 пока закомментировал этот кусок т.к. при этом коде падает стандартный пример ArithmSimplify.cs. #1408 снова открыл
|
|
|
|
|
|
/*var deconstructionType = (patternCase.pattern as deconstructor_pattern).
|
|
|
|
|
|
type as named_type_reference;
|
|
|
|
|
|
if (deconstructionType != null &&
|
|
|
|
|
|
deconstructionType.names != null &&
|
|
|
|
|
|
deconstructionType.names.Count != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var deconstructionTypeName = deconstructionType.names[0].name;
|
|
|
|
|
|
if (usedDeconstructionTypes.Contains(deconstructionTypeName))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SyntaxVisitorError("REPEATED_DECONSTRUCTION_TYPE",
|
|
|
|
|
|
patternCase.pattern.source_context);
|
|
|
|
|
|
}
|
|
|
|
|
|
usedDeconstructionTypes.Add(deconstructionTypeName);
|
|
|
|
|
|
} */
|
|
|
|
|
|
|
|
|
|
|
|
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case const_pattern p:
|
|
|
|
|
|
{
|
|
|
|
|
|
DesugarConstPatternCase(matchWith.expr, patternCase);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case collection_pattern p:
|
|
|
|
|
|
{
|
|
|
|
|
|
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case tuple_pattern p:
|
|
|
|
|
|
{
|
|
|
|
|
|
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
|
|
|
|
|
|
break;
|
2018-12-13 11:11:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
2018-05-11 19:26:55 +03:00
|
|
|
|
if (matchWith.defaultAction != null)
|
|
|
|
|
|
AddDefaultCase(matchWith.defaultAction as statement_list);
|
|
|
|
|
|
|
2018-05-01 19:29:39 +03:00
|
|
|
|
if (desugaredMatchWith == null)
|
2018-05-11 19:26:55 +03:00
|
|
|
|
desugaredMatchWith = new empty_statement();
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
if (typeChecks.Count != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
typeChecks.Add(desugaredMatchWith);
|
|
|
|
|
|
desugaredMatchWith = new statement_list(typeChecks);
|
|
|
|
|
|
}
|
2017-03-06 02:00:50 +03:00
|
|
|
|
// Замена выражения match with на новое несахарное поддерево и его обход
|
2017-12-11 19:26:57 +03:00
|
|
|
|
ReplaceUsingParent(matchWith, desugaredMatchWith);
|
|
|
|
|
|
visit(desugaredMatchWith);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-13 20:49:08 +03:00
|
|
|
|
public override void visit(is_pattern_expr isPatternExpr)
|
|
|
|
|
|
{
|
2018-06-17 14:21:52 +03:00
|
|
|
|
if (GetLocation(isPatternExpr) == PatternLocation.Unknown)
|
|
|
|
|
|
throw new SyntaxVisitorError("PATTERN_MATHING_IS_NOT_SUPPORTED_IN_THIS_CONTEXT", isPatternExpr.source_context);
|
|
|
|
|
|
|
2018-05-16 16:16:42 +03:00
|
|
|
|
Debug.Assert(GetAscendant<statement_list>(isPatternExpr) != null, "Couldn't find statement list in upper nodes");
|
2019-05-24 10:04:17 +03:00
|
|
|
|
|
2018-05-16 00:26:07 +03:00
|
|
|
|
DesugarIsExpression(isPatternExpr);
|
2018-05-13 20:49:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private void DesugarDeconstructorPatternCase(expression matchingExpression, pattern_case patternCase)
|
2017-02-20 13:57:13 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
//var paramCheckExpr = DesugarDeconstructorPatternParameters(patternCase.pattern as deconstructor_pattern);
|
|
|
|
|
|
|
|
|
|
|
|
var isExpression = new is_pattern_expr(matchingExpression, patternCase.pattern, patternCase.source_context);
|
2018-05-17 02:07:10 +03:00
|
|
|
|
var ifCondition = patternCase.condition == null ? (expression)isExpression : bin_expr.LogicalAnd(isExpression, patternCase.condition);
|
|
|
|
|
|
var ifCheck = SubtreeCreator.CreateIf(ifCondition, patternCase.case_action);
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
2018-05-17 02:07:10 +03:00
|
|
|
|
// Добавляем полученные statements в результат
|
|
|
|
|
|
AddDesugaredCaseToResult(ifCheck, ifCheck);
|
2018-05-01 19:29:39 +03:00
|
|
|
|
}
|
2019-05-24 10:04:17 +03:00
|
|
|
|
|
|
|
|
|
|
private type_definition GetTypeDefinitionForConstParam(expression constParamExpr)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (constParamExpr)
|
|
|
|
|
|
{
|
|
|
|
|
|
case string_const type:
|
|
|
|
|
|
return new named_type_reference("string");
|
|
|
|
|
|
case char_const type:
|
|
|
|
|
|
return new named_type_reference("char");
|
|
|
|
|
|
case int32_const type:
|
|
|
|
|
|
return new named_type_reference("integer");
|
|
|
|
|
|
case int64_const type:
|
|
|
|
|
|
return new named_type_reference("integer");
|
|
|
|
|
|
case double_const type:
|
|
|
|
|
|
return new named_type_reference("double");
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private expression DesugarDeconstructorPatternParameters(deconstructor_pattern pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
expression paramCheckExpr = null;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < pattern.parameters.Count; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pattern.parameters[i] is const_pattern_parameter constPattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
var constParamIdent = new ident(NewDeconstructParamId(), pattern.parameters[i].source_context);
|
|
|
|
|
|
|
|
|
|
|
|
var eqParams = new expression_list(
|
|
|
|
|
|
new List<expression>()
|
|
|
|
|
|
{
|
|
|
|
|
|
constPattern.const_param,
|
|
|
|
|
|
constParamIdent
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
var constParamCheck = new method_call(
|
|
|
|
|
|
new dot_node(new ident("object"), new ident("Equals")),
|
|
|
|
|
|
eqParams,
|
|
|
|
|
|
pattern.source_context
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
pattern.parameters[i] = new var_deconstructor_parameter(
|
|
|
|
|
|
constParamIdent,
|
|
|
|
|
|
GetTypeDefinitionForConstParam(constPattern.const_param),
|
|
|
|
|
|
false,
|
|
|
|
|
|
pattern.parameters[i].source_context);
|
|
|
|
|
|
|
|
|
|
|
|
paramCheckExpr = paramCheckExpr == null ? (expression)constParamCheck : bin_expr.LogicalAnd(paramCheckExpr, constParamCheck);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pattern.parameters[i] is wild_card_deconstructor_parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
var wildCardGeneratedParamIdent = new ident(NewDeconstructParamId(), pattern.parameters[i].source_context);
|
|
|
|
|
|
pattern.parameters[i] = new var_deconstructor_parameter(
|
|
|
|
|
|
wildCardGeneratedParamIdent,
|
|
|
|
|
|
null,
|
|
|
|
|
|
false,
|
|
|
|
|
|
pattern.parameters[i].source_context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pattern.parameters[i] is recursive_deconstructor_parameter deconstructor_param)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (deconstructor_param.pattern is deconstructor_pattern deconstructor_pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
var recursiveChecks = DesugarDeconstructorPatternParameters(deconstructor_pattern);
|
|
|
|
|
|
paramCheckExpr = paramCheckExpr == null ?
|
|
|
|
|
|
recursiveChecks :
|
|
|
|
|
|
bin_expr.LogicalAnd(paramCheckExpr, recursiveChecks);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return paramCheckExpr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DesugarConstPatternCase(expression matchingExpression, pattern_case patternCase)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Assert(patternCase.pattern is const_pattern);
|
|
|
|
|
|
var patternExpressionNode = patternCase.pattern as const_pattern;
|
|
|
|
|
|
|
|
|
|
|
|
var statementsToAdd = new List<statement>();
|
|
|
|
|
|
var equalCalls = new List<method_call>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var patternExpression in patternExpressionNode.pattern_expressions.expressions)
|
|
|
|
|
|
{
|
|
|
|
|
|
statementsToAdd.Add(GetTypeCompatibilityCheck(matchingExpression, patternExpression));
|
|
|
|
|
|
|
|
|
|
|
|
// Matching not tuples
|
|
|
|
|
|
var eqParams = new expression_list(
|
|
|
|
|
|
new List<expression>()
|
|
|
|
|
|
{
|
|
|
|
|
|
matchingExpression,
|
|
|
|
|
|
patternExpression
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
equalCalls.Add(
|
|
|
|
|
|
new method_call(
|
|
|
|
|
|
new dot_node(new ident("object"), new ident("Equals")),
|
|
|
|
|
|
eqParams,
|
|
|
|
|
|
patternCase.source_context
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
typeChecks.AddRange(statementsToAdd);
|
|
|
|
|
|
|
|
|
|
|
|
expression orPatternCases = equalCalls[0];
|
|
|
|
|
|
for (int i = 1; i < equalCalls.Count; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
orPatternCases = bin_expr.LogicalOr(orPatternCases, equalCalls[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
var ifCondition = patternCase.condition == null ? orPatternCases : bin_expr.LogicalAnd(orPatternCases, patternCase.condition);
|
|
|
|
|
|
var ifCheck = SubtreeCreator.CreateIf(ifCondition, patternCase.case_action);
|
|
|
|
|
|
|
|
|
|
|
|
// Добавляем полученные statements в результат
|
|
|
|
|
|
AddDesugaredCaseToResult(ifCheck, ifCheck);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private expression GetCollectionItemsEqualCheckBeforeGap(addressed_value matchingExpression,
|
|
|
|
|
|
List<pattern_parameter> toCompare,
|
|
|
|
|
|
CollectionDesugaringResult desugaringResult)
|
|
|
|
|
|
{
|
|
|
|
|
|
var fromIndex = 0;
|
|
|
|
|
|
expression equalChecks = null;
|
|
|
|
|
|
foreach (var param in toCompare)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (param is const_pattern_parameter constParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
var indexerCall = new indexer(
|
|
|
|
|
|
matchingExpression,
|
|
|
|
|
|
new expression_list(
|
|
|
|
|
|
new int32_const(fromIndex, matchingExpression.source_context),
|
|
|
|
|
|
matchingExpression.source_context),
|
|
|
|
|
|
matchingExpression.source_context);
|
|
|
|
|
|
|
|
|
|
|
|
var eqParams = new expression_list(
|
|
|
|
|
|
new List<expression>()
|
|
|
|
|
|
{
|
|
|
|
|
|
indexerCall,
|
|
|
|
|
|
constParam.const_param
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
var equalCall = new method_call(
|
|
|
|
|
|
new dot_node(
|
|
|
|
|
|
new ident("object"),
|
|
|
|
|
|
new ident("Equals")),
|
|
|
|
|
|
eqParams,
|
|
|
|
|
|
matchingExpression.source_context
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
equalChecks = equalChecks == null ? (expression)equalCall : bin_expr.LogicalAnd(equalChecks, equalCall);
|
|
|
|
|
|
desugaringResult.ElemTypeChecks.Add(GetTypeCompatibilityCheck(constParam.const_param, indexerCall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (param is collection_pattern_var_parameter varParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
desugaringResult.VarParametersDeclarations.Add(
|
|
|
|
|
|
new var_statement(varParam.identifier,
|
|
|
|
|
|
GetIndexerCallForCollectionPattern(matchingExpression as addressed_value, fromIndex)));
|
|
|
|
|
|
}
|
|
|
|
|
|
++fromIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
return equalChecks;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private expression GetCollectionItemsEqualCheckAfterGap(addressed_value matchingExpression,
|
|
|
|
|
|
List<pattern_parameter> toCompare,
|
|
|
|
|
|
CollectionDesugaringResult desugaringResult)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elemFromTail = 1;
|
|
|
|
|
|
expression equalChecks = null;
|
|
|
|
|
|
foreach (var param in toCompare)
|
|
|
|
|
|
{
|
|
|
|
|
|
var indexerCall = new indexer(
|
|
|
|
|
|
matchingExpression,
|
|
|
|
|
|
new expression_list(
|
|
|
|
|
|
new bin_expr(
|
|
|
|
|
|
new method_call(
|
|
|
|
|
|
new dot_node(
|
|
|
|
|
|
matchingExpression,
|
|
|
|
|
|
new ident("Count", matchingExpression.source_context)),
|
|
|
|
|
|
new expression_list()),
|
|
|
|
|
|
new int32_const(elemFromTail, matchingExpression.source_context),
|
|
|
|
|
|
Operators.Minus),
|
|
|
|
|
|
matchingExpression.source_context),
|
|
|
|
|
|
matchingExpression.source_context);
|
|
|
|
|
|
|
|
|
|
|
|
if (param is const_pattern_parameter constParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
var eqParams = new expression_list(
|
|
|
|
|
|
new List<expression>()
|
|
|
|
|
|
{
|
|
|
|
|
|
indexerCall,
|
|
|
|
|
|
constParam.const_param
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
var equalCall = new method_call(
|
|
|
|
|
|
new dot_node(
|
|
|
|
|
|
new ident("object"),
|
|
|
|
|
|
new ident("Equals")),
|
|
|
|
|
|
eqParams,
|
|
|
|
|
|
matchingExpression.source_context
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
equalChecks = equalChecks == null ? (expression)equalCall : bin_expr.LogicalAnd(equalChecks, equalCall);
|
|
|
|
|
|
desugaringResult.ElemTypeChecks.Add(GetTypeCompatibilityCheck(constParam.const_param, indexerCall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (param is collection_pattern_var_parameter varParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
desugaringResult.VarParametersDeclarations.Add(
|
|
|
|
|
|
new var_statement(varParam.identifier, indexerCall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
++elemFromTail;
|
|
|
|
|
|
}
|
|
|
|
|
|
return equalChecks;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private expression GetIndexerCallForCollectionPattern(addressed_value matchingExpression, int ind)
|
|
|
|
|
|
{
|
|
|
|
|
|
var indexerCall = new indexer(matchingExpression, new int32_const(ind), matchingExpression.source_context);
|
|
|
|
|
|
return indexerCall;
|
|
|
|
|
|
}
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
2018-05-17 22:49:07 +03:00
|
|
|
|
private ident NewGeneralName() => new ident(GeneratedPatternNamePrefix + "GenVar" + generalVariableCounter++);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
2018-05-17 23:49:50 +03:00
|
|
|
|
private ident NewSuccessName() => new ident(GeneratedPatternNamePrefix + "Success" + successVariableCounter++);
|
2018-05-16 00:26:07 +03:00
|
|
|
|
|
2018-05-17 23:49:50 +03:00
|
|
|
|
private ident NewEndIfName() => new ident(GeneratedPatternNamePrefix + "EndIf" + labelVariableCounter++);
|
2017-12-11 19:26:57 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
private bool IsGenerated(string name) => name.StartsWith(GeneratedPatternNamePrefix);
|
|
|
|
|
|
|
2018-05-11 19:26:55 +03:00
|
|
|
|
private void AddDefaultCase(statement_list statements)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddDesugaredCaseToResult(statements, _previousIf);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-17 02:07:10 +03:00
|
|
|
|
private void AddDesugaredCaseToResult(statement desugaredCase, if_node newIf)
|
2017-12-11 19:26:57 +03:00
|
|
|
|
{
|
|
|
|
|
|
// Если результат пустой, значит это первый case
|
|
|
|
|
|
if (desugaredMatchWith == null)
|
2018-05-17 02:07:10 +03:00
|
|
|
|
desugaredMatchWith = desugaredCase;
|
2017-12-11 19:26:57 +03:00
|
|
|
|
else
|
2018-05-11 19:26:55 +03:00
|
|
|
|
{
|
2018-05-17 02:07:10 +03:00
|
|
|
|
_previousIf.else_body = desugaredCase;
|
2018-05-11 19:26:55 +03:00
|
|
|
|
_previousIf.FillParentsInDirectChilds();
|
|
|
|
|
|
}
|
2017-12-11 19:26:57 +03:00
|
|
|
|
|
|
|
|
|
|
// Запоминаем только что сгенерированный if
|
|
|
|
|
|
_previousIf = newIf;
|
|
|
|
|
|
}
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private DeconstructionDesugaringResult DesugarDeconstructorPattern(deconstructor_pattern pattern, expression matchingExpression)
|
2018-05-06 20:09:36 +03:00
|
|
|
|
{
|
2018-05-15 17:55:57 +03:00
|
|
|
|
Debug.Assert(!pattern.IsRecursive, "All recursive patterns should be desugared into simple patterns at this point");
|
2018-05-11 13:46:59 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
var desugarResult = new DeconstructionDesugaringResult();
|
|
|
|
|
|
var castVariableName = NewGeneralName();
|
|
|
|
|
|
desugarResult.CastVariableDefinition = new var_statement(castVariableName, pattern.type);
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
var successVariableName = NewSuccessName();
|
2018-05-23 10:55:33 +03:00
|
|
|
|
desugarResult.SuccessVariableDefinition = new var_statement(successVariableName, new ident("false"));
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
// делегирование проверки паттерна функции IsTest
|
|
|
|
|
|
desugarResult.TypeCastCheck = SubtreeCreator.CreateSystemFunctionCall(IsTestMethodName, matchingExpression, castVariableName);
|
2018-05-13 20:49:08 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
var parameters = pattern.parameters.Cast<var_deconstructor_parameter>();
|
|
|
|
|
|
foreach (var deconstructedVariable in parameters)
|
|
|
|
|
|
{
|
2018-05-16 00:26:07 +03:00
|
|
|
|
desugarResult.DeconstructionVariables.Add(
|
|
|
|
|
|
new var_def_statement(deconstructedVariable.identifier, deconstructedVariable.type));
|
2018-05-15 17:55:57 +03:00
|
|
|
|
}
|
2018-05-13 20:49:08 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
var deconstructCall = new procedure_call();
|
|
|
|
|
|
deconstructCall.func_name = SubtreeCreator.CreateMethodCall(DeconstructMethodName, castVariableName.name, parameters.Select(x => x.identifier).ToArray());
|
|
|
|
|
|
desugarResult.DeconstructCall = deconstructCall;
|
|
|
|
|
|
|
|
|
|
|
|
return desugarResult;
|
2018-05-13 20:49:08 +03:00
|
|
|
|
}
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private CollectionDesugaringResult DesugarCollectionPattern(collection_pattern pattern, expression matchingExpression)
|
2018-05-13 20:49:08 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
Debug.Assert(!pattern.IsRecursive, "All recursive patterns should be desugared into simple patterns at this point");
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
var desugaringResult = new CollectionDesugaringResult();
|
|
|
|
|
|
var collectionItems = pattern.parameters;
|
|
|
|
|
|
var gapItemMet = false;
|
|
|
|
|
|
var gapIndex = 0;
|
|
|
|
|
|
var exprBeforeGap = new List<pattern_parameter>();
|
|
|
|
|
|
var exprAfterGap = new List<pattern_parameter>();
|
|
|
|
|
|
for (int i = 0; i < collectionItems.Count; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (collectionItems[i] is collection_pattern_gap_parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (gapItemMet)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SyntaxVisitorError("REPEATED_DOTDOT_COLLECTION_PATTERN_EXPR",
|
|
|
|
|
|
pattern.source_context);
|
|
|
|
|
|
}
|
|
|
|
|
|
gapItemMet = true;
|
|
|
|
|
|
gapIndex = i;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (gapItemMet)
|
|
|
|
|
|
{
|
|
|
|
|
|
exprAfterGap.Insert(0, collectionItems[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
exprBeforeGap.Add(collectionItems[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var successMatchingCheck = GetCollectionItemsEqualCheckBeforeGap(
|
|
|
|
|
|
matchingExpression as addressed_value, exprBeforeGap, desugaringResult);
|
|
|
|
|
|
|
|
|
|
|
|
if (gapItemMet && exprAfterGap.Count != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var afterGapEqual = GetCollectionItemsEqualCheckAfterGap(
|
|
|
|
|
|
matchingExpression as addressed_value, exprAfterGap, desugaringResult);
|
|
|
|
|
|
|
|
|
|
|
|
if (afterGapEqual != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
successMatchingCheck = successMatchingCheck == null ?
|
|
|
|
|
|
afterGapEqual :
|
|
|
|
|
|
bin_expr.LogicalAnd(successMatchingCheck, afterGapEqual);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// если добавлять в and, то все равно ран тайм эррор, будто вычисляет все, даже если первое = false
|
|
|
|
|
|
desugaringResult.CollectionLengthCheck = new bin_expr(
|
|
|
|
|
|
new dot_node(matchingExpression as addressed_value, new ident(CountPropertyName), pattern.source_context),
|
|
|
|
|
|
new int32_const(exprBeforeGap.Count + exprAfterGap.Count),
|
|
|
|
|
|
Operators.GreaterEqual,
|
|
|
|
|
|
pattern.source_context
|
|
|
|
|
|
);
|
2018-05-17 00:01:52 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
if (!gapItemMet)
|
|
|
|
|
|
{
|
|
|
|
|
|
var lengthWithoutGapCheck = new bin_expr(
|
|
|
|
|
|
new dot_node(matchingExpression as addressed_value, new ident(CountPropertyName), pattern.source_context),
|
|
|
|
|
|
new int32_const(exprBeforeGap.Count),
|
|
|
|
|
|
Operators.Equal,
|
|
|
|
|
|
pattern.source_context
|
|
|
|
|
|
);
|
|
|
|
|
|
successMatchingCheck = successMatchingCheck == null ?
|
|
|
|
|
|
lengthWithoutGapCheck :
|
|
|
|
|
|
bin_expr.LogicalAnd(lengthWithoutGapCheck, successMatchingCheck);
|
|
|
|
|
|
}
|
2018-10-20 18:59:13 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
desugaringResult.SuccessMatchingCheck = successMatchingCheck == null ?
|
|
|
|
|
|
new bool_const(true) :
|
|
|
|
|
|
successMatchingCheck;
|
|
|
|
|
|
return desugaringResult;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private TupleDesugaringResult DesugarTuplePattern(tuple_pattern pattern, expression matchingExpression)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Assert(!pattern.IsRecursive, "All recursive patterns should be desugared into simple patterns at this point");
|
|
|
|
|
|
var desugaringResult = new TupleDesugaringResult();
|
|
|
|
|
|
var tupleItems = pattern.parameters;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tupleItems.Count; ++i)
|
2018-05-17 00:01:52 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
var tupleItemCall = new dot_node(
|
|
|
|
|
|
matchingExpression as addressed_value,
|
|
|
|
|
|
new ident("Item" + (i + 1).ToString()),
|
|
|
|
|
|
matchingExpression.source_context);
|
|
|
|
|
|
if (tupleItems[i] is tuple_pattern_var_parameter varParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
desugaringResult.VarParametersDeclarations.Add(
|
|
|
|
|
|
new var_statement(
|
|
|
|
|
|
varParam.identifier,
|
|
|
|
|
|
tupleItemCall,
|
|
|
|
|
|
matchingExpression.source_context
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tupleItems[i] is const_pattern_parameter constParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
var eqParams = new expression_list(
|
|
|
|
|
|
new List<expression>()
|
|
|
|
|
|
{
|
|
|
|
|
|
tupleItemCall,
|
|
|
|
|
|
constParam.const_param
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
var equalCall = new method_call(
|
|
|
|
|
|
new dot_node(new ident("object"), new ident("Equals")),
|
|
|
|
|
|
eqParams,
|
|
|
|
|
|
pattern.source_context
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
desugaringResult.SuccessMatchingCheck = desugaringResult.SuccessMatchingCheck == null ?
|
|
|
|
|
|
(expression)equalCall :
|
|
|
|
|
|
bin_expr.LogicalAnd(desugaringResult.SuccessMatchingCheck, equalCall);
|
|
|
|
|
|
desugaringResult.ElemTypeChecks.Add(GetTypeCompatibilityCheck(constParam.const_param, tupleItemCall));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
desugaringResult.TupleLengthCheck = GetTypeCompatibilityCheck(matchingExpression, new int32_const(tupleItems.Count));
|
|
|
|
|
|
|
|
|
|
|
|
if (desugaringResult.SuccessMatchingCheck == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
desugaringResult.SuccessMatchingCheck = new bool_const(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
return desugaringResult;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DesugarIsExpression(is_pattern_expr isPatternExpr)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isPatternExpr.right.IsRecursive)
|
|
|
|
|
|
{
|
|
|
|
|
|
var desugaredRecursiveIs = DesugarRecursiveParameters(isPatternExpr.left, isPatternExpr.right);
|
2018-05-17 00:01:52 +03:00
|
|
|
|
ReplaceUsingParent(isPatternExpr, desugaredRecursiveIs);
|
|
|
|
|
|
desugaredRecursiveIs.visit(this);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2019-05-24 10:04:17 +03:00
|
|
|
|
var patternLocation = GetLocation(isPatternExpr);
|
2018-05-16 00:26:07 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
if (isPatternExpr.right is deconstructor_pattern pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
var constParamCheck = DesugarDeconstructorPatternParameters(isPatternExpr.right as deconstructor_pattern);
|
|
|
|
|
|
pattern.const_params_check = constParamCheck;
|
|
|
|
|
|
}
|
|
|
|
|
|
//AddDefinitionsInUpperStatementList(isPatternExpr, new[] { GetTypeCompatibilityCheck(isPatternExpr) });
|
2018-05-16 00:26:07 +03:00
|
|
|
|
switch (patternLocation)
|
|
|
|
|
|
{
|
|
|
|
|
|
case PatternLocation.IfCondition: DesugarIsExpressionInIfCondition(isPatternExpr); break;
|
|
|
|
|
|
case PatternLocation.Assign: DesugarIsExpressionInAssignment(isPatternExpr); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private expression DesugarRecursiveParameters(expression expression, pattern_node pattern)
|
2018-05-17 00:01:52 +03:00
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
List<pattern_parameter> parameters = pattern.parameters;
|
|
|
|
|
|
expression conjunction = new is_pattern_expr(expression, pattern, pattern.source_context);
|
2018-05-17 00:01:52 +03:00
|
|
|
|
for (int i = 0; i < parameters.Count; i++)
|
|
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
if (parameters[i] is recursive_pattern_parameter parameter)
|
2018-05-17 00:01:52 +03:00
|
|
|
|
{
|
2018-05-23 17:56:19 +03:00
|
|
|
|
//var parameterType = (parameter.pattern as deconstructor_pattern).type;
|
2018-05-17 00:01:52 +03:00
|
|
|
|
var newName = NewGeneralName();
|
2019-05-24 10:04:17 +03:00
|
|
|
|
pattern_parameter varParameter = null;
|
|
|
|
|
|
if (pattern is deconstructor_pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
varParameter = new var_deconstructor_parameter(newName, null, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (pattern is collection_pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
varParameter = new collection_pattern_var_parameter(newName, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (pattern is tuple_pattern)
|
|
|
|
|
|
{
|
|
|
|
|
|
varParameter = new tuple_pattern_var_parameter(newName, null);
|
|
|
|
|
|
}
|
2018-05-17 00:01:52 +03:00
|
|
|
|
parameters[i] = varParameter;
|
|
|
|
|
|
varParameter.Parent = parameters[i];
|
2019-05-24 10:04:17 +03:00
|
|
|
|
conjunction = bin_expr.LogicalAnd(conjunction, DesugarRecursiveParameters(newName, parameter.pattern));
|
2018-05-17 00:01:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return conjunction;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-16 00:26:07 +03:00
|
|
|
|
private void DesugarIsExpressionInAssignment(is_pattern_expr isExpression)
|
|
|
|
|
|
{
|
2019-05-24 10:16:31 +03:00
|
|
|
|
if (!(isExpression.right is deconstructor_pattern))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SyntaxVisitorError("MATCHING_ASSIGN_NOT_SUPPORTED", isExpression.right.source_context);
|
|
|
|
|
|
}
|
2019-05-24 10:04:17 +03:00
|
|
|
|
var statementsToAdd = ProcessDesugaringForDeconstructorPattern(isExpression);
|
2018-05-16 16:16:42 +03:00
|
|
|
|
AddDefinitionsInUpperStatementList(isExpression, statementsToAdd);
|
2018-05-16 00:26:07 +03:00
|
|
|
|
}
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
2018-05-16 00:26:07 +03:00
|
|
|
|
private void DesugarIsExpressionInIfCondition(is_pattern_expr isExpression)
|
|
|
|
|
|
{
|
2019-05-24 10:04:17 +03:00
|
|
|
|
List<statement> statementsToAdd = null;
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
switch (isExpression.right)
|
|
|
|
|
|
{
|
|
|
|
|
|
case deconstructor_pattern dp:
|
|
|
|
|
|
if (dp.const_params_check != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ifToAddConstParamsCheckTo = GetAscendant<if_node>(isExpression);
|
|
|
|
|
|
ifToAddConstParamsCheckTo.condition = bin_expr.LogicalAnd(ifToAddConstParamsCheckTo.condition, dp.const_params_check);
|
|
|
|
|
|
}
|
|
|
|
|
|
statementsToAdd = ProcessDesugaringForDeconstructorPattern(isExpression);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case collection_pattern cp:
|
|
|
|
|
|
statementsToAdd = ProcessDesugaringForCollectionPattern(isExpression);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case tuple_pattern cp:
|
|
|
|
|
|
statementsToAdd = ProcessDesugaringForTuplePattern(isExpression);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-05-16 00:26:07 +03:00
|
|
|
|
|
2018-05-16 16:16:42 +03:00
|
|
|
|
var enclosingIf = GetAscendant<if_node>(isExpression);
|
2018-05-16 00:26:07 +03:00
|
|
|
|
// Если уже обрабатывался ранее (второй встретившийся в том же условии is), то не изменяем if
|
2019-05-24 10:04:17 +03:00
|
|
|
|
if (processedIfNodes.Contains(enclosingIf))
|
2018-05-16 16:16:42 +03:00
|
|
|
|
AddDefinitionsInUpperStatementList(isExpression, statementsToAdd);
|
2018-05-16 00:26:07 +03:00
|
|
|
|
// Иначе помещаем определения и if-then в отдельный блок, а else после этого блока
|
|
|
|
|
|
else
|
2018-05-16 16:16:42 +03:00
|
|
|
|
{
|
2018-05-17 02:07:10 +03:00
|
|
|
|
// Сохраняем родителя, так как он поменяется при вызове ConvertIfNode
|
2018-05-16 16:16:42 +03:00
|
|
|
|
var ifParent = enclosingIf.Parent;
|
2018-05-17 02:03:53 +03:00
|
|
|
|
statement elseBody;
|
|
|
|
|
|
var convertedIf = ConvertIfNode(enclosingIf, statementsToAdd, out elseBody);
|
2018-05-16 16:16:42 +03:00
|
|
|
|
ifParent.ReplaceDescendantUnsafe(enclosingIf, convertedIf);
|
|
|
|
|
|
convertedIf.Parent = ifParent;
|
2018-05-17 02:03:53 +03:00
|
|
|
|
|
|
|
|
|
|
elseBody?.visit(this);
|
2018-05-16 16:16:42 +03:00
|
|
|
|
}
|
2018-05-16 00:26:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private List<statement> ProcessDesugaringForDeconstructorPattern(is_pattern_expr isExpression)
|
|
|
|
|
|
{
|
|
|
|
|
|
var pattern = isExpression.right as deconstructor_pattern;
|
|
|
|
|
|
var desugaringResult = DesugarDeconstructorPattern(pattern, isExpression.left);
|
|
|
|
|
|
/*
|
|
|
|
|
|
var isParent = isExpression.Parent;
|
|
|
|
|
|
expression isReplacement = isExpression;
|
|
|
|
|
|
|
|
|
|
|
|
while (!(isParent is if_node))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isParent is bin_expr binParent)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (binParent.right == isReplacement)
|
|
|
|
|
|
{
|
|
|
|
|
|
isReplacement = new bin_expr(binParent.left, binParent.right, binParent.operation_type, binParent.source_context);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (binParent.left == isReplacement)
|
|
|
|
|
|
{
|
|
|
|
|
|
isReplacement = binParent.left;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
isParent = isParent.Parent;
|
|
|
|
|
|
}*/
|
|
|
|
|
|
ReplaceUsingParent(isExpression, desugaringResult.SuccessVariable);
|
|
|
|
|
|
var statementsToAdd = desugaringResult.GetDeconstructionDefinitions(pattern.source_context);
|
|
|
|
|
|
statementsToAdd.Add(GetMatchedExpressionCheck(isExpression.left));
|
|
|
|
|
|
statementsToAdd.Add(GetTypeCompatibilityCheck(isExpression));
|
|
|
|
|
|
statementsToAdd.Add(desugaringResult.GetPatternCheckWithDeconstrunctorCall());
|
|
|
|
|
|
|
|
|
|
|
|
return statementsToAdd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<statement> ProcessDesugaringForCollectionPattern(is_pattern_expr isExpression)
|
|
|
|
|
|
{
|
|
|
|
|
|
var pattern = isExpression.right as collection_pattern;
|
|
|
|
|
|
var desugaringResult = DesugarCollectionPattern(pattern, isExpression.left);
|
|
|
|
|
|
ReplaceUsingParent(isExpression, desugaringResult.SuccessMatchingCheck);
|
|
|
|
|
|
|
|
|
|
|
|
var statementsToAdd = new List<statement>();
|
|
|
|
|
|
statementsToAdd.AddRange(desugaringResult.VarParametersDeclarations);
|
|
|
|
|
|
statementsToAdd.AddRange(desugaringResult.ElemTypeChecks);
|
|
|
|
|
|
return statementsToAdd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<statement> ProcessDesugaringForTuplePattern(is_pattern_expr isExpression)
|
|
|
|
|
|
{
|
|
|
|
|
|
var pattern = isExpression.right as tuple_pattern;
|
|
|
|
|
|
var desugaringResult = DesugarTuplePattern(pattern, isExpression.left);
|
|
|
|
|
|
ReplaceUsingParent(isExpression, desugaringResult.SuccessMatchingCheck);
|
|
|
|
|
|
|
|
|
|
|
|
var statementsToAdd = new List<statement>();
|
|
|
|
|
|
statementsToAdd.Add(desugaringResult.TupleLengthCheck);
|
|
|
|
|
|
statementsToAdd.AddRange(desugaringResult.VarParametersDeclarations);
|
|
|
|
|
|
statementsToAdd.AddRange(desugaringResult.ElemTypeChecks);
|
|
|
|
|
|
|
|
|
|
|
|
return statementsToAdd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-17 14:21:52 +03:00
|
|
|
|
private semantic_check_sugared_statement_node GetMatchedExpressionCheck(expression matchedExpression)
|
2018-10-20 18:59:13 +03:00
|
|
|
|
=> new semantic_check_sugared_statement_node(SemanticCheckType.MatchedExpression, new List<syntax_tree_node>() { matchedExpression });
|
|
|
|
|
|
|
|
|
|
|
|
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck(is_pattern_expr expression) =>
|
|
|
|
|
|
new semantic_check_sugared_statement_node(SemanticCheckType.MatchedExpressionAndType, new List<syntax_tree_node>() { expression.left, (expression.right as deconstructor_pattern).type });
|
2018-06-17 14:21:52 +03:00
|
|
|
|
|
2019-05-24 10:04:17 +03:00
|
|
|
|
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck(expression expression1, expression expression2) =>
|
|
|
|
|
|
new semantic_check_sugared_statement_node(SemanticCheckType.MatchedExpressionAndExpression, new List<syntax_tree_node>() { expression1, expression2 });
|
|
|
|
|
|
|
|
|
|
|
|
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck(expression tuple, int32_const length) =>
|
|
|
|
|
|
new semantic_check_sugared_statement_node(SemanticCheckType.MatchedTuple, new List<syntax_tree_node>() { tuple, length });
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-05-17 02:03:53 +03:00
|
|
|
|
private statement_list ConvertIfNode(if_node ifNode, List<statement> statementsBeforeIf, out statement elseBody)
|
2018-05-16 00:26:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
// if e then <then> else <else>
|
|
|
|
|
|
//
|
|
|
|
|
|
// переводим в
|
|
|
|
|
|
//
|
|
|
|
|
|
// begin
|
|
|
|
|
|
// statementsBeforeIf
|
|
|
|
|
|
// if e then begin <then>; goto end_if end;
|
|
|
|
|
|
// end
|
|
|
|
|
|
// <else>
|
|
|
|
|
|
// end_if: empty_statement
|
|
|
|
|
|
|
|
|
|
|
|
// if e then <then>
|
|
|
|
|
|
//
|
|
|
|
|
|
// переводим в
|
|
|
|
|
|
//
|
|
|
|
|
|
// begin
|
|
|
|
|
|
// statementsBeforeIf
|
|
|
|
|
|
// if e then <then>
|
|
|
|
|
|
// end
|
|
|
|
|
|
|
|
|
|
|
|
// Добавляем, чтобы на конвертировать еще раз, если потребуется
|
|
|
|
|
|
processedIfNodes.Add(ifNode);
|
|
|
|
|
|
|
|
|
|
|
|
var statementsBeforeAndIf = new statement_list();
|
|
|
|
|
|
statementsBeforeAndIf.AddMany(statementsBeforeIf);
|
|
|
|
|
|
statementsBeforeAndIf.Add(ifNode);
|
|
|
|
|
|
|
|
|
|
|
|
if (ifNode.else_body == null)
|
2018-05-17 02:03:53 +03:00
|
|
|
|
{
|
|
|
|
|
|
elseBody = null;
|
2018-05-16 00:26:07 +03:00
|
|
|
|
return statementsBeforeAndIf;
|
2018-05-17 02:03:53 +03:00
|
|
|
|
}
|
2018-05-16 00:26:07 +03:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = new statement_list();
|
|
|
|
|
|
result.Add(statementsBeforeAndIf);
|
|
|
|
|
|
var endIfLabel = NewEndIfName();
|
|
|
|
|
|
// добавляем метку
|
|
|
|
|
|
if (!(ifNode.then_body is statement_list))
|
|
|
|
|
|
{
|
|
|
|
|
|
ifNode.then_body = new statement_list(ifNode.then_body, ifNode.then_body.source_context);
|
|
|
|
|
|
ifNode.then_body.Parent = ifNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var thenBody = ifNode.then_body as statement_list;
|
|
|
|
|
|
thenBody.Add(new goto_statement(endIfLabel));
|
|
|
|
|
|
// добавляем else и метку за ним
|
|
|
|
|
|
result.Add(ifNode.else_body);
|
|
|
|
|
|
result.Add(new labeled_statement(endIfLabel));
|
2018-05-17 02:03:53 +03:00
|
|
|
|
// Возвращаем else для обхода, т.к. он уже не входит в if
|
|
|
|
|
|
elseBody = ifNode.else_body;
|
2018-05-16 00:26:07 +03:00
|
|
|
|
// удаляем else из if
|
|
|
|
|
|
ifNode.else_body = null;
|
|
|
|
|
|
// Добавляем метку
|
|
|
|
|
|
AddLabel(endIfLabel);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddLabel(ident label)
|
|
|
|
|
|
{
|
2018-05-17 15:20:16 +03:00
|
|
|
|
var block = listNodes.OfType<block>().Last();
|
2018-05-16 00:26:07 +03:00
|
|
|
|
|
|
|
|
|
|
if (block.defs == null)
|
|
|
|
|
|
block.defs = new declarations();
|
|
|
|
|
|
|
2018-05-17 15:20:16 +03:00
|
|
|
|
block.defs.AddFirst(new label_definitions(label));
|
2018-05-15 17:55:57 +03:00
|
|
|
|
}
|
2018-05-13 20:49:08 +03:00
|
|
|
|
|
2018-05-16 16:16:42 +03:00
|
|
|
|
private void AddDefinitionsInUpperStatementList(syntax_tree_node currentNode, IEnumerable<statement> statementsToAdd)
|
2018-05-15 17:55:57 +03:00
|
|
|
|
{
|
|
|
|
|
|
var definitionsAdded = false;
|
2018-05-17 23:49:50 +03:00
|
|
|
|
var ascendants = currentNode.AscendantNodes(true).ToArray();
|
2018-05-13 20:49:08 +03:00
|
|
|
|
|
|
|
|
|
|
// Объявление переменной в ближайшем statement_list
|
2018-05-16 16:16:42 +03:00
|
|
|
|
for (int i = 0; i < ascendants.Length; i++)
|
2018-05-13 20:49:08 +03:00
|
|
|
|
{
|
2018-05-16 16:16:42 +03:00
|
|
|
|
if (ascendants[i] is statement_list statements)
|
2018-05-15 17:55:57 +03:00
|
|
|
|
{
|
|
|
|
|
|
statements.InsertBefore(
|
2018-05-16 16:16:42 +03:00
|
|
|
|
ascendants[i - 1] as statement,
|
2018-05-15 17:55:57 +03:00
|
|
|
|
statementsToAdd);
|
2018-05-16 16:16:42 +03:00
|
|
|
|
|
2018-05-15 17:55:57 +03:00
|
|
|
|
definitionsAdded = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-05-13 20:49:08 +03:00
|
|
|
|
}
|
2018-05-15 17:55:57 +03:00
|
|
|
|
|
|
|
|
|
|
Debug.Assert(definitionsAdded, "Couldn't add definitions");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-16 16:16:42 +03:00
|
|
|
|
private PatternLocation GetLocation(syntax_tree_node node)
|
2018-05-15 17:55:57 +03:00
|
|
|
|
{
|
2018-05-16 16:16:42 +03:00
|
|
|
|
var firstStatement = GetAscendant<statement>(node);
|
2019-05-24 10:04:17 +03:00
|
|
|
|
|
2018-05-16 00:26:07 +03:00
|
|
|
|
switch (firstStatement)
|
|
|
|
|
|
{
|
|
|
|
|
|
case if_node _: return PatternLocation.IfCondition;
|
2018-05-17 23:49:50 +03:00
|
|
|
|
case var_statement _: return PatternLocation.Assign;
|
2019-05-24 10:04:17 +03:00
|
|
|
|
case assign _: return PatternLocation.Assign;
|
2018-05-16 00:26:07 +03:00
|
|
|
|
default: return PatternLocation.Unknown;
|
|
|
|
|
|
}
|
2018-05-15 17:55:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-16 16:16:42 +03:00
|
|
|
|
private T GetAscendant<T>(syntax_tree_node node)
|
2018-05-15 17:55:57 +03:00
|
|
|
|
where T : syntax_tree_node
|
|
|
|
|
|
{
|
2018-05-16 16:16:42 +03:00
|
|
|
|
var current = node.Parent;
|
|
|
|
|
|
while (current != null)
|
2018-05-15 17:55:57 +03:00
|
|
|
|
{
|
2018-05-16 16:16:42 +03:00
|
|
|
|
if (current is T res)
|
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
|
|
current = current.Parent;
|
2018-05-15 17:55:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
2018-05-06 20:09:36 +03:00
|
|
|
|
}
|
2019-05-24 10:04:17 +03:00
|
|
|
|
|
|
|
|
|
|
private string NewDeconstructParamId()
|
|
|
|
|
|
{
|
|
|
|
|
|
return GeneratedPatternNamePrefix + "DeconstructParam" + deconstructParamVariableCounter++.ToString();
|
|
|
|
|
|
}
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-05-11 13:46:59 +03:00
|
|
|
|
|