2017-02-20 13:57:13 +03:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
2026-03-08 18:30:33 +03:00
using PascalABCCompiler.CoreUtils ;
2017-02-20 13:57:13 +03:00
using PascalABCCompiler.SyntaxTree ;
2020-07-14 13:05:02 +03:00
namespace SyntaxVisitors.PatternsVisitors
2017-02-20 13:57:13 +03:00
{
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 }
2023-05-31 14:04:04 +03:00
private const string DeconstructMethodName = "deconstruct" ;
private const string IsTestMethodName = "__TypeCheckAndAssignForIsMatch" ;
private const string WildCardsTupleEqualFunctionName = "__WildCardsTupleEqual" ;
private const string SeqFunctionName = "Seq" ;
private const string CountPropertyName = "Count" ;
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" ;
2019-06-15 12:15:21 +03:00
private const string GeneratedVisitElseBranchVariableName = "<>visitElseBranch" ;
2020-03-09 14:14:53 +03:00
private const string GeneratedMatchExprVariableName = "<>matchExprVariable" ;
2018-05-06 20:09:36 +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 > ( ) ;
2020-03-09 14:14:53 +03:00
private var_statement matchedExprVarDeclaration ;
2018-05-16 00:26:07 +03:00
2019-05-24 10:04:17 +03:00
//const matching
private List < statement > typeChecks = new List < statement > ( ) ;
2026-03-08 18:30:33 +03:00
private readonly GeneratedNamesManager generatedNamesManager ;
private PatternsDesugaringVisitor ( GeneratedNamesManager generatedNamesManager )
{
this . generatedNamesManager = generatedNamesManager ;
}
public static PatternsDesugaringVisitor Create ( GeneratedNamesManager generatedNamesManager ) = > new PatternsDesugaringVisitor ( generatedNamesManager ) ;
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
2020-07-03 06:45:23 +03:00
var matchExprVariableName = NewMatchExprVariableId ( ) ;
2020-03-09 14:14:53 +03:00
matchedExprVarDeclaration = new var_statement (
2020-07-03 06:45:23 +03:00
new ident ( matchExprVariableName , matchWith . expr . source_context ) ,
2020-03-09 14:14:53 +03:00
matchWith . expr . Clone ( ) as expression ,
matchWith . expr . source_context ) ;
2020-07-03 06:45:23 +03:00
ReplaceUsingParent ( matchWith . expr , new ident ( matchExprVariableName , matchWith . expr . source_context ) ) ;
2020-03-09 14:14:53 +03:00
/ * if ( matchWith . Parent is statement_list stl )
{
stl . InsertBefore ( matchWith , matchedExprVarDeclaration ) ;
}
else
{
var enclosingStl = new statement_list ( matchedExprVarDeclaration , matchWith ) ;
enclosingStl . source_context = matchWith . source_context ;
ReplaceUsingParent ( matchWith , enclosingStl ) ;
} * /
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 ;
2020-02-10 15:51:16 +03:00
DefaultDesugarPattern ( matchWith . expr , patternCase ) ;
2018-05-01 19:29:39 +03:00
2020-02-10 15:51:16 +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 снова открыл
2020-02-10 15:51:16 +03:00
var deconstructionType = ( patternCase . pattern as deconstructor_pattern ) .
2019-05-24 10:04:17 +03:00
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 ) ;
2020-02-10 15:51:16 +03:00
}
2019-05-24 10:04:17 +03:00
2020-02-10 15:51:16 +03:00
DefaultDesugarPattern ( matchWith . expr , patternCase ) ;
2019-05-24 10:04:17 +03:00
break ;
}
case const_pattern p :
{
2020-02-10 15:51:16 +03:00
//DesugarConstPatternCase(matchWith.expr, patternCase);
DefaultDesugarPattern ( matchWith . expr , patternCase ) ;
2019-05-24 10:04:17 +03:00
break ;
}
case collection_pattern p :
{
2019-06-15 12:15:21 +03:00
DefaultDesugarPattern ( matchWith . expr , patternCase ) ;
2019-05-24 10:04:17 +03:00
break ;
}
case tuple_pattern p :
{
2019-06-15 12:15:21 +03:00
DefaultDesugarPattern ( matchWith . expr , patternCase ) ;
2019-05-24 10:04:17 +03:00
break ;
2018-12-13 11:11:07 +03:00
}
2020-02-10 15:51:16 +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 ) ;
}
2019-06-15 12:15:21 +03:00
2020-03-09 14:14:53 +03:00
desugaredMatchWith = new statement_list ( matchedExprVarDeclaration , desugaredMatchWith ) ;
2017-03-06 02:00:50 +03:00
// Замена выражения match with на новое несахарное поддерево и е г о обход
2017-12-11 19:26:57 +03:00
ReplaceUsingParent ( matchWith , desugaredMatchWith ) ;
visit ( desugaredMatchWith ) ;
2020-07-14 18:55:14 +03:00
typeChecks . Clear ( ) ; // SSM исправление ошибки #2276
2017-02-20 13:57:13 +03:00
}
2026-03-08 18:30:33 +03:00
private string GenerateNewName ( string name )
2020-06-21 17:12:43 +03:00
{
2026-03-08 18:30:33 +03:00
return generatedNamesManager . GenerateName ( "$RenIsVarYield" , "$" + name ) ;
2020-06-21 17:12:43 +03:00
}
2020-07-14 13:05:02 +03:00
public override void visit ( procedure_definition pd )
{
//ReplaceNamesInIsVarVisitor.New.ProcessNode(pd);
base . visit ( pd ) ;
}
public class StrBool
{
public string name ;
public bool needtorename ;
public StrBool ( string name , bool b = false )
{
this . name = name ;
this . needtorename = b ;
}
}
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
2020-07-14 13:05:02 +03:00
//syntax_tree_node stn = isPatternExpr;
//while (stn != null && !(stn is procedure_definition) && !(stn is function_lambda_definition))
// stn = stn.Parent;
//if (stn is procedure_definition pd && pd.has_yield) // SSM 11/07/20 Надо сделать обход с переименованием!!! Сейчас and не работает в yield + ... is A(var a1)
//{
2020-07-14 18:55:14 +03:00
// SSM 14/07/20
2020-07-14 13:05:02 +03:00
var dict = new Dictionary < string , StrBool > ( StringComparer . InvariantCultureIgnoreCase ) ; // bool - надо ли начинать renaming
2020-07-14 18:55:14 +03:00
var l = new List < statement > ( ) ;
var pp = isPatternExpr . right ? . parameters ;
if ( pp ! = null )
{
foreach ( var p in pp )
2020-06-21 17:12:43 +03:00
{
2020-07-14 18:55:14 +03:00
if ( p is var_deconstructor_parameter vdp )
2020-06-21 17:12:43 +03:00
{
2020-07-14 18:55:14 +03:00
var idClone = vdp . identifier . TypedClone ( ) ;
var idNew = vdp . identifier . TypedClone ( ) ;
idNew . name = GenerateNewName ( idNew . name ) ;
var vs = new var_statement ( idClone , idNew , idClone . source_context ) ;
// проверять, что имя не начинается с $ и если начинается, то ошибка - уже переименовывали такое же!
if ( vdp . identifier . name . StartsWith ( "$" ) ) // SSM 14/07/20
throw new SyntaxVisitorError ( "Повторное объявление" , vdp . identifier . source_context ) ;
dict . Add ( vdp . identifier . name , new StrBool ( idNew . name , false ) ) ;
//vdp.identifier.name = idNew.name; // в следующем цикле переименую
l . Add ( vs ) ;
2020-06-21 17:12:43 +03:00
}
}
2020-07-14 18:55:14 +03:00
}
2020-06-21 17:12:43 +03:00
2020-07-14 18:55:14 +03:00
// SSM 14/07/20
2020-07-14 13:05:02 +03:00
// подниматься пока выражение
syntax_tree_node ex = isPatternExpr ;
syntax_tree_node ex1 = ex ;
while ( ex is expression )
{
ex1 = ex ;
ex = ex . Parent ;
}
ex = ex1 ; // саммое внешнее выражение. В нём и переименовать!
var nams = ex . DescendantNodes ( ) . Where ( stn = > stn is ident ) . Cast < ident > ( ) ;
foreach ( var n in nams )
{
// надо как-то пробросить до первой is_var
if ( dict . ContainsKey ( n . name ) )
{
var isvar = GetAscendant < is_pattern_expr > ( n ) ;
if ( isvar ! = null )
{
dict [ n . name ] . needtorename = true ; // всё - можно переименовывать далее
n . name = dict [ n . name ] . name ; // переименовываем в is_var
continue ;
}
if ( ! dict [ n . name ] . needtorename ) // если еще не дошли до is_var, то это какая-то внешняя и не переименовываем
continue ;
if ( n . Parent is dot_node dn & & dn . left = = n ) // т.е . не переименовываем только если ident - в правой части dot_node
{
// переименовываем
n . name = dict [ n . name ] . name ;
}
else
{
// переименовываем
n . name = dict [ n . name ] . name ;
}
}
}
2020-07-14 18:55:14 +03:00
var stat = GetAscendant < statement > ( isPatternExpr ) ;
if ( stat is if_node ifn )
{
//l.Add(ifn.then_body);
if ( ! ( ifn . then_body is statement_list ) )
2020-06-21 17:12:43 +03:00
{
2020-07-14 18:55:14 +03:00
ifn . then_body = new statement_list ( ifn . then_body ) ;
2020-06-21 17:12:43 +03:00
}
2020-07-14 18:55:14 +03:00
( ifn . then_body as statement_list ) . list . InsertRange ( 0 , l ) ;
}
else
{
l . Insert ( 0 , stat ) ;
foreach ( var x in l )
x . Parent = stat . Parent ;
var stl = stat . Parent as statement_list ;
2021-02-08 22:30:22 +03:00
if ( stl ! = null )
stl . ReplaceInList ( stat , l ) ;
2021-02-09 09:15:54 +03:00
else if ( stat is var_statement )
2021-02-08 22:30:22 +03:00
throw new SyntaxVisitorError ( "EMBEDDED_STATEMENT_CANNOT_BE_A_DECLARATION" , stat . source_context ) ;
2020-07-14 18:55:14 +03:00
}
2020-07-14 13:05:02 +03:00
//}
2020-06-21 17:12:43 +03:00
2020-07-11 17:11:27 +03:00
2020-06-21 17:12:43 +03:00
//ReplaceStatement(stat, l); // тут нельзя.
2018-05-16 00:26:07 +03:00
DesugarIsExpression ( isPatternExpr ) ;
2018-05-13 20:49:08 +03:00
}
2019-06-15 12:15:21 +03:00
private void DefaultDesugarPattern ( 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 )
{
2023-05-29 14:54:03 +03:00
/ * switch ( constParamExpr )
2019-05-24 10:04:17 +03:00
{
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" ) ;
2023-05-29 14:54:03 +03:00
} * /
if ( constParamExpr is string_const )
return new named_type_reference ( "string" ) ;
if ( constParamExpr is char_const )
return new named_type_reference ( "char" ) ;
if ( constParamExpr is int32_const )
return new named_type_reference ( "integer" ) ;
if ( constParamExpr is int64_const )
return new named_type_reference ( "integer" ) ;
if ( constParamExpr is double_const )
return new named_type_reference ( "double" ) ;
2019-05-24 10:04:17 +03:00
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 > ( ) ;
2019-05-25 12:30:15 +03:00
var equalCalls = new List < bin_expr > ( ) ;
2019-05-24 10:04:17 +03:00
foreach ( var patternExpression in patternExpressionNode . pattern_expressions . expressions )
{
statementsToAdd . Add ( GetTypeCompatibilityCheck ( matchingExpression , patternExpression ) ) ;
2019-05-25 12:30:15 +03:00
2019-05-24 10:04:17 +03:00
equalCalls . Add (
2019-05-25 12:30:15 +03:00
new bin_expr ( matchingExpression , patternExpression , Operators . Equal , patternCase . source_context
2019-05-24 10:04:17 +03:00
)
) ;
}
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 ) ;
2019-05-25 12:30:15 +03:00
desugaringResult . ElemTypeChecks . Add ( GetTypeCompatibilityCheck ( indexerCall , constParam . const_param ) ) ;
2019-05-24 10:04:17 +03:00
}
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 ) ;
2019-05-25 12:30:15 +03:00
desugaringResult . ElemTypeChecks . Add ( GetTypeCompatibilityCheck ( indexerCall , constParam . const_param ) ) ;
2019-05-24 10:04:17 +03:00
}
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
2026-03-08 18:30:33 +03:00
private ident NewGeneralName ( SourceContext sc ) = > new ident ( generatedNamesManager . GenerateName ( GeneratedPatternNamePrefix + "GenVar" ) , sc ) ;
2017-02-20 13:57:13 +03:00
2026-03-08 18:30:33 +03:00
private ident NewSuccessName ( SourceContext sc ) = > new ident ( generatedNamesManager . GenerateName ( GeneratedPatternNamePrefix + "Success" ) , sc ) ;
2018-05-16 00:26:07 +03:00
2026-03-08 18:30:33 +03:00
// private ident NewEndIfName(SourceContext sc) => new ident(GeneratedPatternNamePrefix + "EndIf" + labelVariableCounter++, sc);
2017-12-11 19:26:57 +03:00
2026-03-08 18:30:33 +03:00
// private bool IsGenerated(string name) => name.StartsWith(GeneratedPatternNamePrefix);
2018-05-15 17:55:57 +03:00
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 ( ) ;
2020-06-18 08:23:11 +03:00
var castVariableName = NewGeneralName ( pattern . source_context ) ;
desugarResult . CastVariableDefinition = new var_statement ( castVariableName , pattern . type , pattern . type . source_context ) ;
2018-05-06 20:09:36 +03:00
2020-06-18 08:23:11 +03:00
var successVariableName = NewSuccessName ( matchingExpression . source_context ) ;
desugarResult . SuccessVariableDefinition = new var_statement ( successVariableName , new ident ( "false" ) , successVariableName . source_context ) ;
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 (
2020-06-18 08:23:11 +03:00
new var_def_statement ( deconstructedVariable . identifier , deconstructedVariable . type , deconstructedVariable . identifier . source_context ) ) ;
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 ( ) ;
2026-02-02 12:01:18 +03:00
deconstructCall . func_name = SubtreeCreator . CreateMethodCallWithQualifier ( DeconstructMethodName , castVariableName . name , parameters . Select ( x = > x . identifier ) . ToArray ( ) ) ;
2018-05-15 17:55:57 +03:00
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 ) ;
}
}
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 ,
2020-06-24 09:41:52 +03:00
new ident ( "Item" + ( i + 1 ) . ToString ( ) , matchingExpression . source_context ) , // SSM 24/06/20
2019-05-24 10:04:17 +03:00
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 ) ;
2019-05-25 12:30:15 +03:00
desugaringResult . ElemTypeChecks . Add ( GetTypeCompatibilityCheck ( tupleItemCall , constParam . const_param ) ) ;
2019-05-24 10:04:17 +03:00
}
}
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;
2020-06-18 08:23:11 +03:00
var newName = NewGeneralName ( parameter . source_context ) ;
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
2023-05-29 14:54:03 +03:00
/ * switch ( isExpression . right )
2019-05-24 10:04:17 +03:00
{
case deconstructor_pattern dp :
if ( dp . const_params_check ! = null )
{
var ifToAddConstParamsCheckTo = GetAscendant < if_node > ( isExpression ) ;
2023-05-29 14:54:03 +03:00
ifToAddConstParamsCheckTo . condition =
bin_expr . LogicalAnd ( ifToAddConstParamsCheckTo . condition , dp . const_params_check ) ;
2019-05-24 10:04:17 +03:00
}
statementsToAdd = ProcessDesugaringForDeconstructorPattern ( isExpression ) ;
break ;
case collection_pattern cp :
statementsToAdd = ProcessDesugaringForCollectionPattern ( isExpression ) ;
break ;
case tuple_pattern cp :
statementsToAdd = ProcessDesugaringForTuplePattern ( isExpression ) ;
break ;
2020-02-10 15:51:16 +03:00
case const_pattern cp :
statementsToAdd = ProcessDesugaringForConstPattern ( isExpression ) ;
break ;
2023-05-29 14:54:03 +03:00
} * /
if ( isExpression . right is 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 ) ;
}
else if ( isExpression . right is collection_pattern )
{
statementsToAdd = ProcessDesugaringForCollectionPattern ( isExpression ) ;
}
else if ( isExpression . right is tuple_pattern )
{
statementsToAdd = ProcessDesugaringForTuplePattern ( isExpression ) ;
}
else if ( isExpression . right is const_pattern )
{
statementsToAdd = ProcessDesugaringForConstPattern ( isExpression ) ;
2019-05-24 10:04:17 +03:00
}
2018-05-16 00:26:07 +03:00
2023-05-29 14:54:03 +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
}
2020-02-10 15:51:16 +03:00
private List < statement > ProcessDesugaringForConstPattern ( is_pattern_expr isExpression )
{
var patternExpressionNode = isExpression . right as const_pattern ;
var statementsToAdd = new List < statement > ( ) ;
var equalCalls = new List < bin_expr > ( ) ;
foreach ( var patternExpression in patternExpressionNode . pattern_expressions . expressions )
{
statementsToAdd . Add ( GetTypeCompatibilityCheck ( isExpression . left , patternExpression ) ) ;
equalCalls . Add (
new bin_expr ( isExpression . left , patternExpression , Operators . Equal , isExpression . source_context
)
) ;
}
typeChecks . AddRange ( statementsToAdd ) ;
expression orPatternCases = equalCalls [ 0 ] ;
for ( int i = 1 ; i < equalCalls . Count ; + + i )
{
orPatternCases = bin_expr . LogicalOr ( orPatternCases , equalCalls [ i ] ) ;
}
ReplaceUsingParent ( isExpression , orPatternCases ) ;
return statementsToAdd ;
}
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 ) ;
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 )
2020-07-14 18:55:14 +03:00
{
return new semantic_check_sugared_statement_node ( SemanticCheckType . MatchedExpression , new List < syntax_tree_node > ( ) { matchedExpression } ) ;
}
2018-06-17 14:21:52 +03:00
2020-07-14 18:55:14 +03:00
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck ( is_pattern_expr expression )
{
return new semantic_check_sugared_statement_node ( SemanticCheckType . MatchedExpressionAndType , new List < syntax_tree_node > ( ) { expression . left , ( expression . right as deconstructor_pattern ) . type } ) ;
}
2019-05-24 10:04:17 +03:00
2020-07-14 18:55:14 +03:00
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck ( expression expression1 , expression expression2 )
{
return new semantic_check_sugared_statement_node ( SemanticCheckType . MatchedExpressionAndExpression , new List < syntax_tree_node > ( ) { expression1 , expression2 } ) ;
}
2019-05-24 10:04:17 +03:00
2020-07-14 18:55:14 +03:00
private semantic_check_sugared_statement_node GetTypeCompatibilityCheck ( expression tuple , int32_const length )
{
return new semantic_check_sugared_statement_node ( SemanticCheckType . MatchedTuple , new List < syntax_tree_node > ( ) { tuple , length } ) ;
}
2019-06-15 12:15:21 +03:00
private bool IsNestedIfWithExtendedIs ( if_node ifNode )
{
var parent = ifNode . Parent ;
while ( parent ! = null )
{
if ( parent is statement_list stList & &
IsVisitElseBranchStatementListDeclaration ( stList ) )
{
return true ;
}
parent = parent . Parent ;
}
return false ;
}
private bool IsVisitElseBranchStatementListDeclaration ( statement_list stList )
{
return stList . list ! = null & & stList . list [ 0 ] ! = null & &
stList . list [ 0 ] is var_statement visitElseVarStatement & &
visitElseVarStatement . var_def . vars . idents [ 0 ] . name . Equals ( GeneratedVisitElseBranchVariableName ) ;
}
2019-05-24 10:04:17 +03:00
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
2019-06-15 12:15:21 +03:00
// var <>visitElseBranch := true;
// begin
// <>visitElseBranch := true;
// statementsBeforeIf
// if e then begin <then>; <>visitElseBranch := false; end;
// end
// if <>visitElseBranch then <else>
2018-05-16 00:26:07 +03:00
// end
// if e then <then>
//
// переводим в
//
// begin
// statementsBeforeIf
// if e then <then>
// end
2019-06-15 12:15:21 +03:00
// Добавляем объявление <>visitElseBranch если мы находимся в первом в цепочке if, который не является вложенным
List < statement > visitElseStatList = null ;
if ( ifNode . else_body ! = null & &
! ( ifNode . Parent is if_node ifParentNode & &
ifParentNode . condition is ident ifParentNodeIdent & &
ifParentNodeIdent . name . Equals ( GeneratedVisitElseBranchVariableName ) ) & &
! IsNestedIfWithExtendedIs ( ifNode ) )
{
visitElseStatList = new List < statement > ( ) ;
visitElseStatList . Add (
new var_statement (
new ident ( GeneratedVisitElseBranchVariableName , ifNode . source_context ) ,
new bool_const ( true , ifNode . source_context ) ,
ifNode . source_context )
) ;
}
2018-05-16 00:26:07 +03:00
// Добавляем, чтобы на конвертировать еще раз, если потребуется
processedIfNodes . Add ( ifNode ) ;
2019-06-15 12:15:21 +03:00
if ( ifNode . else_body ! = null )
{
statementsBeforeIf . Add ( new assign (
new ident ( GeneratedVisitElseBranchVariableName , ifNode . source_context ) ,
new bool_const ( true , ifNode . source_context ) ,
Operators . Assignment ,
ifNode . source_context ) ) ;
}
2018-05-16 00:26:07 +03:00
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 ;
2019-06-15 12:15:21 +03:00
if ( visitElseStatList ! = null )
{
visitElseStatList . Add ( statementsBeforeAndIf ) ;
statementsBeforeAndIf = new statement_list ( visitElseStatList ) ;
}
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 ) ;
2020-06-18 08:23:11 +03:00
//var endIfLabel = NewEndIfName();
2019-06-15 12:15:21 +03:00
2018-05-16 00:26:07 +03:00
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 ;
2019-06-15 12:15:21 +03:00
thenBody . Add ( new assign (
new ident ( GeneratedVisitElseBranchVariableName , thenBody . source_context ) ,
new bool_const ( false , thenBody . source_context ) ,
Operators . Assignment ,
thenBody . source_context ) ) ;
// добавляем else
result . Add (
new if_node (
new ident ( GeneratedVisitElseBranchVariableName , ifNode . else_body . source_context ) ,
ifNode . else_body ,
null ,
ifNode . else_body . source_context ) ) ;
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 ;
2019-06-15 12:15:21 +03:00
if ( visitElseStatList ! = null )
{
visitElseStatList . Add ( result ) ;
result = new statement_list ( visitElseStatList ) ;
}
2018-05-16 00:26:07 +03:00
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
2023-05-29 14:54:03 +03:00
/ * switch ( firstStatement )
2018-05-16 00:26:07 +03:00
{
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 ;
2023-05-29 14:54:03 +03:00
} * /
if ( firstStatement is if_node )
return PatternLocation . IfCondition ;
if ( firstStatement is var_statement )
return PatternLocation . Assign ;
if ( firstStatement is assign )
return PatternLocation . Assign ;
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 ( )
{
2026-03-08 18:30:33 +03:00
return generatedNamesManager . GenerateName ( GeneratedPatternNamePrefix + "DeconstructParam" ) ;
2019-05-24 10:04:17 +03:00
}
2020-07-03 06:45:23 +03:00
private string NewMatchExprVariableId ( )
{
2026-03-08 18:30:33 +03:00
return generatedNamesManager . GenerateName ( GeneratedMatchExprVariableName + "matchExprVariableCounter" ) ;
2020-07-03 06:45:23 +03:00
}
2017-02-20 13:57:13 +03:00
}
}
2018-05-11 13:46:59 +03:00