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;
|
|
|
|
|
|
|
|
|
|
|
|
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; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <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; }
|
|
|
|
|
|
|
|
|
|
|
|
public ident CastVariable
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return CastVariableDefinition.var_def.vars.list[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-20 13:57:13 +03:00
|
|
|
|
public class MatchWithVisitor : BaseChangeVisitor
|
|
|
|
|
|
{
|
2018-05-06 20:09:36 +03:00
|
|
|
|
private const string DeconstructMethodName = "Deconstruct";
|
|
|
|
|
|
|
2017-03-06 02:00:50 +03:00
|
|
|
|
private int _variableCounter = 0;
|
2017-12-11 19:26:57 +03:00
|
|
|
|
private if_node _previousIf;
|
|
|
|
|
|
private statement_list desugaredMatchWith;
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
|
|
|
|
|
public static MatchWithVisitor New => new MatchWithVisitor();
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2017-03-06 02:00:50 +03:00
|
|
|
|
// Преобразование из сахара в известную конструкцию каждого case
|
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
|
|
|
|
|
|
|
|
|
|
if (patternCase.pattern is deconstructor_pattern)
|
2018-05-06 20:09:36 +03:00
|
|
|
|
// TODO: introduce a variable for expression and cache it
|
2018-05-01 19:29:39 +03:00
|
|
|
|
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
|
|
|
|
|
if (desugaredMatchWith == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-11 19:26:57 +03:00
|
|
|
|
void DesugarTypePatternCase(expression matchingExpression, pattern_case patternCase)
|
2017-02-20 13:57:13 +03:00
|
|
|
|
{
|
|
|
|
|
|
Debug.Assert(patternCase.pattern is type_pattern);
|
|
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
//var result = new statement_list();
|
|
|
|
|
|
//// создание фиктивной переменной необходимого типа
|
|
|
|
|
|
//var pattern = (type_pattern) patternCase.pattern;
|
|
|
|
|
|
|
|
|
|
|
|
//// Конструируем условие мэтчинга
|
|
|
|
|
|
//expression matchCondition = isTest;
|
|
|
|
|
|
//if (patternCase.condition == null)
|
|
|
|
|
|
// matchCondition = isTest;
|
|
|
|
|
|
//else
|
|
|
|
|
|
//// Если есть секция when - добавляем ее в условие
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // Переименовываем идентификатор, т.к. мы сгенерировали внутреннее имя
|
|
|
|
|
|
// patternCase.condition.RenameIdentifierInDescendants(pattern.identifier.name, matchResultVariableName.name);
|
|
|
|
|
|
// matchCondition = new bin_expr(isTest, patternCase.condition, Operators.LogicalAND);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//// Создание узла if с объявлением переменной из паттерна и присвоение ей значения
|
|
|
|
|
|
//// сгенерированной переменной
|
|
|
|
|
|
//var patternVarDef = new var_statement(pattern.identifier, matchResultVariableName);
|
|
|
|
|
|
//// Создание тела if из объявления переменной и соттветствующего тела case
|
|
|
|
|
|
//var ifCheck = SubtreeCreator.CreateIf(matchCondition, new statement_list(patternVarDef, patternCase.case_action));
|
|
|
|
|
|
//result.Add(ifCheck);
|
|
|
|
|
|
|
|
|
|
|
|
//// Добавляем полученные statements в результат
|
|
|
|
|
|
//AddDesugaredCaseToResult(result, ifCheck);
|
2018-05-01 19:29:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DesugarDeconstructorPatternCase(expression matchingExpression, pattern_case patternCase)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Assert(patternCase.pattern is deconstructor_pattern);
|
|
|
|
|
|
|
|
|
|
|
|
var result = new statement_list();
|
2018-05-06 20:09:36 +03:00
|
|
|
|
var pattern = patternCase.pattern as deconstructor_pattern;
|
2018-05-01 19:29:39 +03:00
|
|
|
|
// создание фиктивной переменной необходимого типа
|
2018-05-06 20:09:36 +03:00
|
|
|
|
var desugaredPattern = DesugarPattern(pattern, matchingExpression);
|
|
|
|
|
|
result.Add(desugaredPattern.CastVariableDefinition);
|
2018-05-01 19:29:39 +03:00
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
if (patternCase.condition != null)
|
2018-05-01 19:29:39 +03:00
|
|
|
|
// Если есть секция when - добавляем ее в условие
|
|
|
|
|
|
{
|
2018-05-06 20:09:36 +03:00
|
|
|
|
// TODO: generate check for 'when'
|
2018-05-01 19:29:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
// Создание тела if из объявлений переменных, вызова Deconstruct и соответствующего тела case
|
|
|
|
|
|
var ifBody = new statement_list();
|
2018-05-11 13:46:59 +03:00
|
|
|
|
ifBody.Add(new desugared_deconstruction(desugaredPattern.DeconstructionVariables, desugaredPattern.CastVariable, patternCase.pattern.source_context));
|
2018-05-06 20:09:36 +03:00
|
|
|
|
ifBody.Add(desugaredPattern.DeconstructCall);
|
|
|
|
|
|
ifBody.Add(patternCase.case_action);
|
|
|
|
|
|
var ifCheck = SubtreeCreator.CreateIf(desugaredPattern.TypeCastCheck, ifBody);
|
2018-05-11 13:46:59 +03:00
|
|
|
|
|
2017-12-11 19:26:57 +03:00
|
|
|
|
result.Add(ifCheck);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
|
2017-12-11 19:26:57 +03:00
|
|
|
|
// Добавляем полученные statements в результат
|
|
|
|
|
|
AddDesugaredCaseToResult(result, ifCheck);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private ident GenerateIdent()
|
|
|
|
|
|
{
|
2018-05-11 13:46:59 +03:00
|
|
|
|
return new ident("<>patternGenVar" + _variableCounter++);
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
2017-12-11 19:26:57 +03:00
|
|
|
|
|
|
|
|
|
|
private void AddDesugaredCaseToResult(statement_list statements, if_node newIf)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Если результат пустой, значит это первый case
|
|
|
|
|
|
if (desugaredMatchWith == null)
|
|
|
|
|
|
desugaredMatchWith = statements;
|
|
|
|
|
|
else
|
|
|
|
|
|
_previousIf.else_body = statements;
|
|
|
|
|
|
|
|
|
|
|
|
// Запоминаем только что сгенерированный if
|
|
|
|
|
|
_previousIf = newIf;
|
|
|
|
|
|
}
|
2018-05-06 20:09:36 +03:00
|
|
|
|
|
|
|
|
|
|
private DeconstructionDesugaringResult DesugarPattern(deconstructor_pattern pattern, expression matchingExpression)
|
|
|
|
|
|
{
|
|
|
|
|
|
var desugarResult = new DeconstructionDesugaringResult();
|
|
|
|
|
|
var castVariableName = GenerateIdent();
|
|
|
|
|
|
desugarResult.CastVariableDefinition = new var_statement(castVariableName, pattern.type);
|
2018-05-11 13:46:59 +03:00
|
|
|
|
|
2018-05-06 20:09:36 +03:00
|
|
|
|
// делегирование проверки паттерна функции IsTest
|
|
|
|
|
|
desugarResult.TypeCastCheck = SubtreeCreator.CreateSystemFunctionCall("IsTest", matchingExpression, castVariableName);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var deconstructedVariable in pattern.parameters)
|
|
|
|
|
|
desugarResult.DeconstructionVariables.Add(
|
|
|
|
|
|
new var_def_statement(deconstructedVariable.identifier, deconstructedVariable.type));
|
|
|
|
|
|
|
|
|
|
|
|
var deconstructCall = new procedure_call();
|
|
|
|
|
|
deconstructCall.func_name = SubtreeCreator.CreateMethodCall(DeconstructMethodName, castVariableName.name, pattern.parameters.Select(x => x.identifier).ToArray());
|
|
|
|
|
|
desugarResult.DeconstructCall = deconstructCall;
|
|
|
|
|
|
|
|
|
|
|
|
return desugarResult;
|
|
|
|
|
|
}
|
2017-02-20 13:57:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-05-11 13:46:59 +03:00
|
|
|
|
|