pascalabcnet/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutionClassGenerator.cs
Александр Земляк 1f4b44c2c0
Исправление ошибок при перекомпиляции pcu файлов (#3398)
* Move yield string constants to StringConstants class

* Add GeneratedNamesManager class to store all generated names during unit compilation

* Make GeneratedNamesManager class non static

* Add Utils project to installer files

* Add GeneratedNamesManager usage in CapturedVariablesSubstitutionsManager

* Move GeneratedNamesManager initialization in CompilationUnit constructor

* More GeneratedNamesManager usage

* QuestionPointDesugarVisitor fix
2026-03-08 18:30:33 +03:00

852 lines
46 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using PascalABCCompiler.SemanticTree;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.TreeRealization;
using static PascalABCCompiler.StringConstants;
using PascalABCCompiler.CoreUtils;
namespace TreeConverter.LambdaExpressions.Closure
{
internal class CapturedVariablesSubstitutionClassGenerator
{
private readonly CapturedVariablesTreeNode _capturedVariablesRootTreeNode;
private readonly Dictionary<int, ScopeClassDefinition> _capturedVarsClassDefs;
private readonly List<CapturedVariablesTreeNodeLambdaScope> _lambdasToBeAddedAsMethods;
private const string GeneratedClassPrefix = "<>local_variables_class_";
private const string GeneratedUpperClassPrefix = "<>local_variables_class_UPPER_";
private readonly Dictionary<SubstitutionKey, dot_node> _substitutions;
private readonly List<LambdaReferencesSubstitutionInfo> _lambdaIdReferences = new List<LambdaReferencesSubstitutionInfo>();
private readonly List<RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo> _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo = new List<RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo>();
private readonly GeneratedNamesManager generatedNamesManager;
public class VariableSubstitutionsInfo
{
public Dictionary<int, ScopeClassDefinition> GeneratedScopeClassesInfo
{
get;
set;
}
public Dictionary<SubstitutionKey, dot_node> SubstitutionsInfo
{
get;
set;
}
public List<CapturedVariablesTreeNodeLambdaScope> LambdasToBeAddedAsMethods
{
get;
set;
}
public Dictionary<string, Tuple<string, class_field, semantic_node>> ConvertingClassNonPublicMembersMapping
{
get; set;
}
}
public class ScopeClassDefinition
{
private const string GeneratedSubstitutingFieldPrefix = "<>local_variables_"; //это поле для того, чтобы заменять в текущем блоке, где захватывались переменные, левую часть dot_node
public List<CapturedVariablesTreeNodeLambdaScope> NestedLambdas { get; set; }
public syntax_tree_node CorrespondingSyntaxTreeNode
{
get;
private set;
}
public type_declaration ClassDeclaration
{
get;
private set;
}
private string _generatedSubstitutingFieldName;
public string GeneratedSubstitutingFieldName
{
get {
return _generatedSubstitutingFieldName ??
(_generatedSubstitutingFieldName =
generatedNamesManager.GenerateName(GeneratedSubstitutingFieldPrefix));
}
}
private string _generatedUpperClassFieldName;
public string GeneratedUpperClassFieldName
{
get
{
return _generatedUpperClassFieldName ??
(_generatedUpperClassFieldName =
generatedNamesManager.GenerateName(GeneratedUpperClassPrefix));
}
}
private var_statement _generatedVarStatementForScope;
public var_statement GeneratedVarStatementForScope
{
get
{
if (_generatedVarStatementForScope == null)
{
var newVarDefSyntaxTreeNode =
SyntaxTreeBuilder.BuildSimpleVarDef(GeneratedSubstitutingFieldName, ClassDeclaration.type_name.name);
newVarDefSyntaxTreeNode.inital_value =
new new_expr(SyntaxTreeBuilder.BuildSimpleType(ClassDeclaration.type_name.name),
new expression_list(), null);
_generatedVarStatementForScope = new var_statement(newVarDefSyntaxTreeNode);
}
return _generatedVarStatementForScope;
}
}
public assign AssignNodeForUpperClassFieldInitialization
{
get;
set;
}
public CapturedVariablesTreeNode CorrespondingTreeNode { get; private set; }
private readonly GeneratedNamesManager generatedNamesManager;
public ScopeClassDefinition(syntax_tree_node syntaxTreeNode,
type_declaration classDeclaration,
CapturedVariablesTreeNode correspondingTreeNode,
GeneratedNamesManager generatedNamesManager,
string generatedSubstitutingFieldName = null)
{
CorrespondingSyntaxTreeNode = syntaxTreeNode;
ClassDeclaration = classDeclaration;
_generatedSubstitutingFieldName = generatedSubstitutingFieldName;
CorrespondingTreeNode = correspondingTreeNode;
NestedLambdas = new List<CapturedVariablesTreeNodeLambdaScope>();
this.generatedNamesManager = generatedNamesManager;
}
}
private class LambdaReferencesSubstitutionInfo
{
public CapturedVariablesTreeNodeLambdaScope LambdaScope { get; set; }
public string VarName { get; set; }
public syntax_tree_node SyntaxTreeNodeWithVarDeclaration { get; set; }
public dot_node DotNode { get; set; }
}
private class RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo
{
public CapturedVariablesTreeNode TreeNode { get; set; }
public string Varname { get; set; }
public syntax_tree_node NodeWithVarDecl { get; set; }
}
public CapturedVariablesSubstitutionClassGenerator(CapturedVariablesTreeNode capturedVariablesRootTreeNode, GeneratedNamesManager generatedNamesManager)
{
_capturedVariablesRootTreeNode = capturedVariablesRootTreeNode;
_capturedVarsClassDefs = new Dictionary<int, ScopeClassDefinition>();
_substitutions = new Dictionary<SubstitutionKey, dot_node>();
_lambdasToBeAddedAsMethods = new List<CapturedVariablesTreeNodeLambdaScope>();
this.generatedNamesManager = generatedNamesManager;
}
private string GeneratedClassName
{
get
{
return generatedNamesManager.GenerateName(GeneratedClassPrefix);
}
}
private void VisitCapturedVar(CapturedVariablesTreeNode scope, CapturedVariablesTreeNode.CapturedSymbolInfo symbolInfo)
{
var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name; //.ToLower();
var ff = symbolInfo.SymbolInfo.sym_info.GetType();
var isSelfWordInClass = scope is CapturedVariablesTreeNodeClassScope && varName.Equals(self_word, symbolInfo.SymbolInfo.scope.StringComparison);
SourceContext sourceCtxt = null;
if (symbolInfo.SymbolInfo.sym_info.location != null)
sourceCtxt = new SourceContext(symbolInfo.SymbolInfo.sym_info.location.begin_line_num, symbolInfo.SymbolInfo.sym_info.location.begin_column_num,
symbolInfo.SymbolInfo.sym_info.location.end_line_num, symbolInfo.SymbolInfo.sym_info.location.end_column_num);
foreach (var referencingLambda in symbolInfo.ReferencingLambdas.OrderByDescending(rl => rl.ScopeIndex))
{
if (scope != referencingLambda.ParentNode)
{
var upperScopesStack = new Stack<CapturedVariablesTreeNode>();
var crawlUpScope = referencingLambda.ParentNode;
var anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope;
while (crawlUpScope != null && crawlUpScope != scope && !anotherLambdaIsOnTheWay)
{
upperScopesStack.Push(crawlUpScope);
crawlUpScope = crawlUpScope.ParentNode;
anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope;
}
if (anotherLambdaIsOnTheWay || crawlUpScope == null)
{
continue;
}
var upperScopeWhereVarsAreCaptured = scope;
var upperScopeWhereVarsAreCapturedClass =
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex].ClassDeclaration;
var ClassName = upperScopeWhereVarsAreCapturedClass.type_name;
var ClassField = symbolInfo.SymbolInfo.sym_info as class_field;
var substKey = new SubstitutionKey(varName, symbolInfo.SyntaxTreeNodeWithVarDeclaration,
scope.CorrespondingSyntaxTreeNode);
if (!_substitutions.ContainsKey(substKey))
{
// SSM 22.10.17 Тут ошибка в случае захвата классовых полей - первый параметр должен быть не self, а имя класса
if (ClassField != null && ClassField.IsStatic)
_substitutions.Add(substKey, new dot_node(ClassName, new ident(varName)));// sc не заполнен, что плохо!
else
_substitutions.Add(substKey,
new dot_node(
new ident(
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt), new ident(varName, sourceCtxt), sourceCtxt));
}
while (upperScopesStack.Count != 0)
{
var foundScopeWhereVarsWereCaptured = false;
while (upperScopesStack.Count != 0 && !foundScopeWhereVarsWereCaptured)
{
if (
upperScopesStack.Peek()
.VariablesDefinedInScope.Exists(var => var.ReferencingLambdas.Count > 0))
{
foundScopeWhereVarsWereCaptured = true;
}
else
{
var curScope = upperScopesStack.Pop();
if (upperScopeWhereVarsAreCaptured == scope &&
upperScopeWhereVarsAreCaptured is CapturedVariablesTreeNodeClassScope)
{
continue;
}
substKey = new SubstitutionKey(varName, symbolInfo.SyntaxTreeNodeWithVarDeclaration,
curScope.CorrespondingSyntaxTreeNode);
dot_node dotnode;
if (upperScopeWhereVarsAreCaptured != scope)
{
dotnode =
new dot_node(
new ident(
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt),
new ident(
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedUpperClassFieldName, sourceCtxt), sourceCtxt);
var nodeForDotNodeCalc = upperScopeWhereVarsAreCaptured.ParentNode;
while (nodeForDotNodeCalc != scope)
{
if (_capturedVarsClassDefs.ContainsKey(nodeForDotNodeCalc.ScopeIndex) &&
_capturedVarsClassDefs[nodeForDotNodeCalc.ScopeIndex]
.AssignNodeForUpperClassFieldInitialization != null)
{
dotnode = new dot_node(dotnode,
new ident(
_capturedVarsClassDefs[
nodeForDotNodeCalc.ScopeIndex]
.GeneratedUpperClassFieldName));
}
nodeForDotNodeCalc = nodeForDotNodeCalc.ParentNode;
}
if (!isSelfWordInClass)
{
dotnode = new dot_node(dotnode, new ident(varName, sourceCtxt), sourceCtxt);
}
}
else
{
dotnode = new dot_node(new ident(
_capturedVarsClassDefs[
upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt),
new ident(varName, sourceCtxt), sourceCtxt);
}
if (!_substitutions.ContainsKey(substKey))
{
_substitutions.Add(substKey, dotnode);
}
}
}
if (foundScopeWhereVarsWereCaptured)
{
var nextNodeWhereVarsAreCaptured = upperScopesStack.Pop();
if (!_capturedVarsClassDefs.ContainsKey(nextNodeWhereVarsAreCaptured.ScopeIndex))
{
var classDef = SyntaxTreeBuilder.BuildClassDefinition();
var typeDeclaration = new type_declaration(GeneratedClassName, classDef);
_capturedVarsClassDefs.Add(nextNodeWhereVarsAreCaptured.ScopeIndex,
new ScopeClassDefinition(
nextNodeWhereVarsAreCaptured.CorrespondingSyntaxTreeNode,
typeDeclaration,
nextNodeWhereVarsAreCaptured,
generatedNamesManager));
}
var nextNodeWhereVarsAreCapturedClass =
(class_definition)
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex].ClassDeclaration
.type_def;
if (
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.AssignNodeForUpperClassFieldInitialization == null && !(ClassField != null && ClassField.IsStatic))
{
var fieldType =
SyntaxTreeBuilder.BuildSimpleType(upperScopeWhereVarsAreCapturedClass.type_name.name);
var field =
SyntaxTreeBuilder.BuildClassFieldsSection(
new List<ident>
{
new ident(
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.GeneratedUpperClassFieldName, sourceCtxt)
},
new List<type_definition> {fieldType});
nextNodeWhereVarsAreCapturedClass.body.Add(field);
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.AssignNodeForUpperClassFieldInitialization =
new assign(
new dot_node(
new ident(
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt),
new ident(
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.GeneratedUpperClassFieldName), sourceCtxt),
new ident(
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt),
sourceCtxt);
}
substKey = new SubstitutionKey(varName, symbolInfo.SyntaxTreeNodeWithVarDeclaration,
nextNodeWhereVarsAreCaptured.CorrespondingSyntaxTreeNode);
var dot =
new dot_node(
new ident(
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.GeneratedSubstitutingFieldName),
new ident(
_capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
.GeneratedUpperClassFieldName));
var nodeForDotNodeCalculation = nextNodeWhereVarsAreCaptured.ParentNode;
while (nodeForDotNodeCalculation != scope)
{
if (_capturedVarsClassDefs.ContainsKey(nodeForDotNodeCalculation.ScopeIndex) &&
_capturedVarsClassDefs[nodeForDotNodeCalculation.ScopeIndex]
.AssignNodeForUpperClassFieldInitialization != null)
{
dot = new dot_node(dot,
new ident(
_capturedVarsClassDefs[nodeForDotNodeCalculation.ScopeIndex]
.GeneratedUpperClassFieldName, sourceCtxt), sourceCtxt);
}
nodeForDotNodeCalculation = nodeForDotNodeCalculation.ParentNode;
}
if (!isSelfWordInClass)
{
dot = new dot_node(dot, new ident(varName, sourceCtxt), sourceCtxt);
}
if (!_substitutions.ContainsKey(substKey))
{
if (ClassField != null && ClassField.IsStatic)
_substitutions.Add(substKey, new dot_node(ClassName, new ident(varName, sourceCtxt), sourceCtxt));// sc не заполнен, что плохо!
else
_substitutions.Add(substKey, dot);
}
upperScopeWhereVarsAreCaptured = nextNodeWhereVarsAreCaptured;
upperScopeWhereVarsAreCapturedClass =
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex].ClassDeclaration;
}
}
if (!(upperScopeWhereVarsAreCaptured == scope &&
upperScopeWhereVarsAreCaptured is CapturedVariablesTreeNodeClassScope))
{
if (upperScopeWhereVarsAreCaptured != scope)
{
dot_node dotnode1 = null;
if (ClassField != null && ClassField.IsStatic)
dotnode1 = new dot_node(ClassName, new ident(varName));
else
dotnode1 = new dot_node(
new ident(PascalABCCompiler.StringConstants.self_word, sourceCtxt),
new ident(
_capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
.GeneratedUpperClassFieldName, sourceCtxt), sourceCtxt);
if (upperScopeWhereVarsAreCaptured != scope)
{
var nodeForDotNodeCalc = upperScopeWhereVarsAreCaptured.ParentNode;
while (nodeForDotNodeCalc != scope)
{
if (_capturedVarsClassDefs.ContainsKey(nodeForDotNodeCalc.ScopeIndex) &&
_capturedVarsClassDefs[nodeForDotNodeCalc.ScopeIndex]
.AssignNodeForUpperClassFieldInitialization != null)
{
dotnode1 = new dot_node(dotnode1,
new ident(
_capturedVarsClassDefs[nodeForDotNodeCalc.ScopeIndex]
.GeneratedUpperClassFieldName, sourceCtxt), sourceCtxt);
}
nodeForDotNodeCalc = nodeForDotNodeCalc.ParentNode;
}
}
if (!isSelfWordInClass)
{
var classScope = scope as CapturedVariablesTreeNodeClassScope;
if (classScope != null)
{
Tuple<string, class_field, semantic_node> publicProperty;
if (classScope.NonPublicMembersNamesMapping.TryGetValue(varName, out publicProperty))
{
dotnode1 = new dot_node(dotnode1.left, new ident(publicProperty.Item1, sourceCtxt), sourceCtxt); // SSM #869 добавил .left - была ошибка
}
else
{
if (!(ClassField != null && ClassField.IsStatic))
dotnode1 = new dot_node(dotnode1, new ident(varName, sourceCtxt), sourceCtxt); // ?? dotnode1.left ??
}
}
else
{
dotnode1 = new dot_node(dotnode1, new ident(varName, sourceCtxt), sourceCtxt); // ?? dotnode1.left ??
}
}
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
}
else
{
var dotnode1 = new dot_node(
new ident(PascalABCCompiler.StringConstants.self_word, sourceCtxt),
new ident(varName, sourceCtxt), sourceCtxt);
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
}
}
if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue ||
upperScopeWhereVarsAreCaptured.ScopeIndex >
referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod)
{
referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod =
upperScopeWhereVarsAreCaptured.ScopeIndex;
}
}
else
{
if (!_capturedVarsClassDefs.ContainsKey(scope.ScopeIndex))
{
var classDef = SyntaxTreeBuilder.BuildClassDefinition();
var typeDeclaration = new type_declaration(GeneratedClassName, classDef);
_capturedVarsClassDefs.Add(scope.ScopeIndex,
new ScopeClassDefinition(
scope.CorrespondingSyntaxTreeNode,
typeDeclaration,
scope,
generatedNamesManager));
}
var substKey = new SubstitutionKey(varName, symbolInfo.SyntaxTreeNodeWithVarDeclaration,
scope.CorrespondingSyntaxTreeNode);
if (!_substitutions.ContainsKey(substKey))
{
if (!isSelfWordInClass)
{
string propertyName = null;
var classScope = scope as CapturedVariablesTreeNodeClassScope;
if (classScope != null)
{
Tuple<string, class_field, semantic_node> publicProperty;
if (classScope.NonPublicMembersNamesMapping.TryGetValue(varName, out publicProperty))
{
propertyName = publicProperty.Item1;
}
}
_substitutions.Add(substKey,
new dot_node(
new ident(
_capturedVarsClassDefs[scope.ScopeIndex]
.GeneratedSubstitutingFieldName, sourceCtxt), new ident(propertyName ?? varName, sourceCtxt), sourceCtxt));
}
}
var dotnode1 = new dot_node(
new ident(PascalABCCompiler.StringConstants.self_word, sourceCtxt),
new ident(varName, sourceCtxt), sourceCtxt);
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue ||
scope.ScopeIndex > referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod)
{
referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod = scope.ScopeIndex;
}
}
if (!_lambdasToBeAddedAsMethods.Contains(referencingLambda))
{
_lambdasToBeAddedAsMethods.Add(referencingLambda);
}
}
}
private void AddReferencesToIdentInLambda(type_declaration upperScopeWhereVarsAreCapturedClass, CapturedVariablesTreeNode scope, string varName, syntax_tree_node syntaxTreeNodeWithVarDeclaration, dot_node substDotNode, bool nestedLambda)
{
/*#if DEBUG
var pp = scope.ToString().IndexOf("TreeNode");
var ss = scope.ToString().Remove(0, pp + 8).Replace("Scope"," ");
var cn = "";
if (scope.ChildNodes.Count>0)
cn = "Childs: "+ scope.ChildNodes.Aggregate("",(s, x) => s + x.ScopeIndex.ToString() + " ");
System.IO.File.AppendAllText("d:\\w.txt", "AddR enter: " + ss + scope.ScopeIndex + " " + cn + "" +scope.CorrespondingSyntaxTreeNode + "\n");
#endif*/
for (var i = 0; i < scope.ChildNodes.Count; i++)
{
if (!(scope.ChildNodes[i] is CapturedVariablesTreeNodeLambdaScope))
{
var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration,
scope.ChildNodes[i].CorrespondingSyntaxTreeNode);
if (_capturedVarsClassDefs.ContainsKey(scope.ChildNodes[i].ScopeIndex))
{
var cl = _capturedVarsClassDefs[scope.ChildNodes[i].ScopeIndex];
if (cl.AssignNodeForUpperClassFieldInitialization == null)
{
var fieldType =
SyntaxTreeBuilder.BuildSimpleType(upperScopeWhereVarsAreCapturedClass.type_name.name);
var field =
SyntaxTreeBuilder.BuildClassFieldsSection(
new List<ident>
{
new ident(cl.GeneratedUpperClassFieldName)
},
new List<type_definition> { fieldType });
var clClass = (class_definition) cl.ClassDeclaration.type_def;
clClass.body.Add(field);
cl.AssignNodeForUpperClassFieldInitialization =
new assign(
new dot_node(new ident(cl.GeneratedSubstitutingFieldName),new ident(cl.GeneratedUpperClassFieldName)),
new ident(PascalABCCompiler.StringConstants.self_word));
}
}
if (!_substitutions.ContainsKey(substKey))
{
/*#if DEBUG
System.IO.File.AppendAllText("d:\\w.txt", "1 substitutions.Add: " + substKey + " " + substDotNode + "\n");
#endif*/
_substitutions.Add(substKey, substDotNode);
}
AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda);
}
else
{
var scopeAsLambda = scope.ChildNodes[i] as CapturedVariablesTreeNodeLambdaScope;
if (scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue)
{
dot_node substDotNode1;
if (!nestedLambda)
{
var parts = new Stack<ident>();
var dn = substDotNode;
parts.Push((ident)dn.right);
while (!(dn.left is ident && dn.right is ident))
{
dn = (dot_node)dn.left;
parts.Push((ident)dn.right);
}
substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), parts.Pop());
while (parts.Count > 0)
{
substDotNode1 = new dot_node(substDotNode1, parts.Pop());
}
}
else
{
var parts = new Stack<ident>();
var dn = substDotNode;
parts.Push((ident)dn.right);
while (!(dn.left is ident && dn.right is ident))
{
dn = (dot_node)dn.left;
parts.Push((ident)dn.right);
}
parts.Push((ident)dn.left);
substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), parts.Pop());
while (parts.Count > 0)
{
substDotNode1 = new dot_node(substDotNode1, parts.Pop());
}
}
var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration,
scope.ChildNodes[0].CorrespondingSyntaxTreeNode);
if (!_substitutions.ContainsKey(substKey))
{
/*#if DEBUG
System.IO.File.AppendAllText("d:\\w.txt", "2 substitutions.Add: " + substKey + " " + substDotNode + "\n");
#endif*/
_substitutions.Add(substKey, substDotNode1);
}
AddReferencesToIdentInLambda(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration, scopeAsLambda.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode1, true);
}
else
{
// SSM 25.06.19 fix #1988 - заменил ошибочное scope.ChildNodes[0] на scope.ChildNodes[i]
AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda);
}
}
}
/*#if DEBUG
System.IO.File.AppendAllText("d:\\w.txt", "AddR exit: " + scope.ScopeIndex+"\n");
#endif*/
}
private void VisitTreeAndBuildClassDefinitions(CapturedVariablesTreeNode currentNode)
{
var variablesFromThisScopeWhichWereCaptured = currentNode
.VariablesDefinedInScope
.Where(var => var.ReferencingLambdas.Count > 0)
.ToList();
if (variablesFromThisScopeWhichWereCaptured.Count > 0)
{
if (currentNode is CapturedVariablesTreeNodeClassScope)
{
if (!_capturedVarsClassDefs.ContainsKey(currentNode.ScopeIndex))
{
var classDef = SyntaxTreeBuilder.BuildClassDefinition();
var typeDeclaration = new type_declaration(((CapturedVariablesTreeNodeClassScope)currentNode).ClassName, classDef);
_capturedVarsClassDefs.Add(currentNode.ScopeIndex,
new ScopeClassDefinition(currentNode.CorrespondingSyntaxTreeNode,
typeDeclaration,
currentNode,
generatedNamesManager,
PascalABCCompiler.StringConstants.self_word));
}
}
else
{
if (!_capturedVarsClassDefs.ContainsKey(currentNode.ScopeIndex))
{
var classDef = SyntaxTreeBuilder.BuildClassDefinition();
var typeDeclaration = new type_declaration(GeneratedClassName, classDef);
_capturedVarsClassDefs.Add(currentNode.ScopeIndex,
new ScopeClassDefinition(currentNode.CorrespondingSyntaxTreeNode,
typeDeclaration,
currentNode,
generatedNamesManager));
}
var vars = variablesFromThisScopeWhichWereCaptured
.Select(field => field.SymbolInfo.sym_info as IVAriableDefinitionNode)
.ToList();
var fieldNames = vars
.Select(var => new ident(var.name,(var as local_variable)?.loc ?? null))
.ToList();
var fieldTypes = vars
.Select(var => SyntaxTreeBuilder.BuildSemanticType(var.type))
.ToList();
var classFields = SyntaxTreeBuilder.BuildClassFieldsSection(fieldNames, fieldTypes);
((class_definition) _capturedVarsClassDefs[currentNode.ScopeIndex].ClassDeclaration.type_def).body
.Add(
classFields);
if (currentNode is CapturedVariablesTreeNodeProcedureScope)
{
var constructorSection = SyntaxTreeBuilder.BuildSimpleConstructorSection(fieldNames,
fieldNames.Select(
id =>
new ident("_" +
id.name,id.source_context))
.ToList(),
fieldTypes);
((class_definition) _capturedVarsClassDefs[currentNode.ScopeIndex].ClassDeclaration.type_def)
.body.Add(constructorSection);
}
}
foreach (var capturedVar in variablesFromThisScopeWhichWereCaptured)
{
VisitCapturedVar(currentNode, capturedVar);
}
}
foreach (CapturedVariablesTreeNode childNode in currentNode.ChildNodes)
{
VisitTreeAndBuildClassDefinitions(childNode);
}
if (variablesFromThisScopeWhichWereCaptured.Count > 0)
{
var vars = variablesFromThisScopeWhichWereCaptured
.Select(x =>
new
{
IVarDefinitionNode = x.SymbolInfo.sym_info as IVAriableDefinitionNode,
VarDeclNode = x.SyntaxTreeNodeWithVarDeclaration
})
.Where(x => x.IVarDefinitionNode != null)
.ToList();
foreach (var var in vars)
{
foreach (CapturedVariablesTreeNode childNode in currentNode.ChildNodes)
{
_rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo.Add(
new RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo
{
TreeNode = childNode,
Varname = var.IVarDefinitionNode.name,
NodeWithVarDecl = var.VarDeclNode
});
}
}
}
}
private void RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(CapturedVariablesTreeNode node, string varName, syntax_tree_node nodeWithVarDecl)
{
if (node is CapturedVariablesTreeNodeLambdaScope)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(node.ChildNodes[0], varName, nodeWithVarDecl);
return;
}
if (!(node is CapturedVariablesTreeNodeBlockScope ||
node is CapturedVariablesTreeNodeForScope ||
node is CapturedVariablesTreeNodeForEachScope))
{
return;
}
var substKey = new SubstitutionKey(varName, nodeWithVarDecl, node.CorrespondingSyntaxTreeNode);
if (!_substitutions.ContainsKey(substKey))
{
var parentNode = node.ParentNode;
var isReferenceFound = false;
SubstitutionKey parentSubstKey = null;
while (parentNode != null && !isReferenceFound)
{
parentSubstKey = new SubstitutionKey(varName, nodeWithVarDecl, parentNode.CorrespondingSyntaxTreeNode);
if (_substitutions.ContainsKey(parentSubstKey))
{
isReferenceFound = true;
}
else
{
parentNode = parentNode.ParentNode;
}
}
if (isReferenceFound)
{
_substitutions.Add(substKey, _substitutions[parentSubstKey]);
}
}
foreach (CapturedVariablesTreeNode childNode in node.ChildNodes)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(childNode, varName, nodeWithVarDecl);
}
}
public VariableSubstitutionsInfo GenerateSubstitutions()
{
VisitTreeAndBuildClassDefinitions(_capturedVariablesRootTreeNode);
foreach (var ls in _lambdaIdReferences.Where(x => x.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue))
{
AddReferencesToIdentInLambda(_capturedVarsClassDefs[ls.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration,
ls.LambdaScope.ChildNodes[0], ls.VarName, ls.SyntaxTreeNodeWithVarDeclaration, ls.DotNode, false);
}
foreach (var r in _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(r.TreeNode, r.Varname, r.NodeWithVarDecl);
}
return new VariableSubstitutionsInfo
{
GeneratedScopeClassesInfo = _capturedVarsClassDefs,
SubstitutionsInfo = _substitutions,
LambdasToBeAddedAsMethods = _lambdasToBeAddedAsMethods,
ConvertingClassNonPublicMembersMapping = _capturedVariablesRootTreeNode is CapturedVariablesTreeNodeClassScope ?
((CapturedVariablesTreeNodeClassScope)_capturedVariablesRootTreeNode).NonPublicMembersNamesMapping : null
};
}
}
}