diff --git a/SyntaxTree/tree/TreeHelper.cs b/SyntaxTree/tree/TreeHelper.cs index 8ef38b6b4..3c1c4ea97 100644 --- a/SyntaxTree/tree/TreeHelper.cs +++ b/SyntaxTree/tree/TreeHelper.cs @@ -33,7 +33,7 @@ namespace PascalABCCompiler.SyntaxTree DirectDescendants } - public enum SemanticCheckType { MatchedExpression, MatchedExpressionAndType } + public enum SemanticCheckType { MatchedExpression, MatchedExpressionAndType, MatchedExpressionAndExpression } public partial class syntax_tree_node { diff --git a/SyntaxVisitors/SugarVisitors/PatternsDesugaringVisitor.cs b/SyntaxVisitors/SugarVisitors/PatternsDesugaringVisitor.cs index 6191901a3..4d9ca57be 100644 --- a/SyntaxVisitors/SugarVisitors/PatternsDesugaringVisitor.cs +++ b/SyntaxVisitors/SugarVisitors/PatternsDesugaringVisitor.cs @@ -74,9 +74,11 @@ namespace SyntaxVisitors.SugarVisitors private if_node _previousIf; private statement desugaredMatchWith; - private List processedIfNodes = new List(); + //const matching + private List typeChecks = new List(); + public static PatternsDesugaringVisitor New => new PatternsDesugaringVisitor(); public override void visit(match_with matchWith) @@ -129,6 +131,11 @@ namespace SyntaxVisitors.SugarVisitors if (desugaredMatchWith == null) desugaredMatchWith = new empty_statement(); + if (typeChecks.Count != 0) + { + typeChecks.Add(desugaredMatchWith); + desugaredMatchWith = new statement_list(typeChecks); + } // Замена выражения match with на новое несахарное поддерево и его обход ReplaceUsingParent(matchWith, desugaredMatchWith); visit(desugaredMatchWith); @@ -162,6 +169,7 @@ namespace SyntaxVisitors.SugarVisitors var patternExpressionNode = patternCase.pattern as const_pattern; //var tuple_pattern_case = patternExpressionNode.pattern_expression as method_call; + var statementsToAdd = new List(); var equalCalls = new List(); foreach (var patternExpression in patternExpressionNode.pattern_expressions.expressions) { @@ -179,7 +187,9 @@ namespace SyntaxVisitors.SugarVisitors patternCase.source_context ) ); + statementsToAdd.Add(GetTypeCompatibilityCheck(matchingExpression, patternExpression)); } + typeChecks.AddRange(statementsToAdd); expression orPatternCases = equalCalls[0]; for (int i = 1; i < equalCalls.Count; ++i) { @@ -187,7 +197,18 @@ namespace SyntaxVisitors.SugarVisitors } var ifCondition = patternCase.condition == null ? orPatternCases : bin_expr.LogicalAnd(orPatternCases, patternCase.condition); var ifCheck = SubtreeCreator.CreateIf(ifCondition, patternCase.case_action); - + /* + if (_previousIf != null) + { + AddDefinitionsInUpperStatementList(ifCheck, statementsToAdd); + } + else + { + statement emptySt = new empty_statement(); + ConvertIfNode(ifCheck, statementsToAdd, out emptySt); + ifCheck = processedIfNodes[0]; + } + */ // Добавляем полученные statements в результат AddDesugaredCaseToResult(ifCheck, ifCheck); } @@ -341,6 +362,9 @@ namespace SyntaxVisitors.SugarVisitors private semantic_check_sugared_statement_node GetTypeCompatibilityCheck(is_pattern_expr expression) => new semantic_check_sugared_statement_node(SemanticCheckType.MatchedExpressionAndType, new List() { expression.left, (expression.right as deconstructor_pattern).type }); + private semantic_check_sugared_statement_node GetTypeCompatibilityCheck(expression expression1, expression expression2) => + new semantic_check_sugared_statement_node(SemanticCheckType.MatchedExpressionAndExpression, new List() { expression1, expression2 }); + private statement_list ConvertIfNode(if_node ifNode, List statementsBeforeIf, out statement elseBody) { // if e then else diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs index 2326db8be..3c9b3df2d 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Patterns.cs @@ -261,5 +261,22 @@ namespace PascalABCCompiler.TreeConverter AddError(get_location(matchedExpression), "EXPRESSION_OF_TYPE_{0}_CANNOT_BE_MATCHED_AGAINST_PATTERN_WITH_TYPE_{1}", expression.name, type.name); } + + private void CheckIfCanBeMatched(expression matchedExpression, expression patternExpression) + { + var patternType = convert_strong(patternExpression).type; + var expressionType = convert_strong(matchedExpression).type; + + var expressionTypeName = expressionType.name; + var patternTypeName = patternType.name; + + if (type_table.is_derived(patternType, expressionType) || + type_table.is_derived(expressionType, patternType) || + AreTheSameType(patternType, expressionType) || + (expressionTypeName.StartsWith("Tuple") && patternTypeName.StartsWith("Tuple"))) + return; + + AddError(get_location(matchedExpression), "EXPRESSION_OF_TYPE_{0}_CANNOT_BE_MATCHED_AGAINST_PATTERN_WITH_TYPE_{1}", expressionType.name, patternType.name); + } } } diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index b4e366b37..214db0530 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -20012,6 +20012,12 @@ namespace PascalABCCompiler.TreeConverter var type = st.lst[1] as type_definition; CheckIfCanBeMatched(expr, type); } + else if (st.typ is SemanticCheckType.MatchedExpressionAndExpression) + { + var matchedExpr = st.lst[0] as expression; + var patternExpr = st.lst[1] as expression; + CheckIfCanBeMatched(matchedExpr, patternExpr); + } // !Patterns else {