// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (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.TreeConverter; using PascalABCCompiler.TreeRealization; namespace TreeConverter.LambdaExpressions.Closure { internal class CapturedVariablesSubstitutionClassGenerator { private readonly CapturedVariablesTreeNode _capturedVariablesRootTreeNode; private readonly Dictionary _capturedVarsClassDefs; private readonly List _lambdasToBeAddedAsMethods; private const string GeneratedClassPrefix = "<>local_variables_class_"; private const string GeneratedUpperClassPrefix = "<>local_variables_class_UPPER_"; private static int _generatedClassCounter; private static int _generatedUpperClassCounter; private readonly Dictionary _substitutions; private readonly List _lambdaIdReferences = new List(); private readonly List _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo = new List(); public static void Reset() { _generatedClassCounter = 0; _generatedUpperClassCounter = 0; } public class VariableSubstitutionsInfo { public Dictionary GeneratedScopeClassesInfo { get; set; } public Dictionary SubstitutionsInfo { get; set; } public List LambdasToBeAddedAsMethods { get; set; } public Dictionary> ConvertingClassNonPublicMembersMapping { get; set; } } public class ScopeClassDefinition { private const string GeneratedSubstitutingFieldPrefix = "<>local_variables_"; //это поле для того, чтобы заменять в текущем блоке, где захватывались переменные, левую часть dot_node private static int _generatedSubstitutingFieldCounter; public List 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 = GeneratedSubstitutingFieldPrefix + _generatedSubstitutingFieldCounter++); } } private string _generatedUpperClassFieldName; public string GeneratedUpperClassFieldName { get { return _generatedUpperClassFieldName ?? (_generatedUpperClassFieldName = GeneratedUpperClassPrefix + _generatedUpperClassCounter++); } } 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; } public ScopeClassDefinition(syntax_tree_node syntaxTreeNode, type_declaration classDeclaration, CapturedVariablesTreeNode correspondingTreeNode, string generatedSubstitutingFieldName = null) { CorrespondingSyntaxTreeNode = syntaxTreeNode; ClassDeclaration = classDeclaration; _generatedSubstitutingFieldName = generatedSubstitutingFieldName; CorrespondingTreeNode = correspondingTreeNode; NestedLambdas = new List(); } } 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) { _capturedVariablesRootTreeNode = capturedVariablesRootTreeNode; _capturedVarsClassDefs = new Dictionary(); _substitutions = new Dictionary(); _lambdasToBeAddedAsMethods = new List(); } private string GeneratedClassName { get { return GeneratedClassPrefix + _generatedClassCounter++; } } 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 == compiler_string_consts.self_word; 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(); 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)); } 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 { new ident( _capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex] .GeneratedUpperClassFieldName, sourceCtxt) }, new List {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(compiler_string_consts.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 publicProperty; if (classScope.NonPublicMembersNamesMapping.TryGetValue(varName, out publicProperty)) { dotnode1 = new dot_node(dotnode1, new ident(publicProperty.Item1, sourceCtxt), sourceCtxt); } else { if (!(ClassField != null && ClassField.IsStatic)) dotnode1 = new dot_node(dotnode1, new ident(varName, sourceCtxt), sourceCtxt); } } else { dotnode1 = new dot_node(dotnode1, new ident(varName, sourceCtxt), sourceCtxt); } } _lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo { LambdaScope = referencingLambda, VarName = varName, SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration, DotNode = dotnode1 }); } else { var dotnode1 = new dot_node( new ident(compiler_string_consts.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)); } 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 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(compiler_string_consts.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) { 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 { new ident(cl.GeneratedUpperClassFieldName) }, new List { 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(compiler_string_consts.self_word)); } } if (!_substitutions.ContainsKey(substKey)) { _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(); 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(); 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)) { _substitutions.Add(substKey, substDotNode1); } AddReferencesToIdentInLambda(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration, scopeAsLambda.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode1, true); } else { AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda); } } } } 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, compiler_string_consts.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)); } var vars = variablesFromThisScopeWhichWereCaptured .Select(field => field.SymbolInfo.sym_info as IVAriableDefinitionNode) .ToList(); var fieldNames = vars .Select(var => new ident(var.name)) .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)) .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 }; } } }