private void SubstituteForEachLoopVariables()
        {
            var forEachScopes =
                _capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeForEachScope)
                                                .Select(n => (CapturedVariablesTreeNodeForEachScope)n.Value)
                                                .ToList();

            foreach (var forEachScope in forEachScopes)
            {
                var forEachNode = forEachScope.CorrespondingSyntaxTreeNode as foreach_stmt;
                if (forEachNode != null)
                {
                    CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
                    if (_generatedScopeClassesInfo.TryGetValue(forEachScope.ScopeIndex, out generatedClass))
                    {
                        var nodesToAdd = new List<statement>();
                        var bodyStmtList = (statement_list)forEachNode.stmt;
                        nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
                        if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
                        {
                            nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
                        }

                        var substDotNode = new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName), new ident(forEachNode.identifier.name));
                        var assignNode = new assign(substDotNode, new ident(forEachNode.identifier.name));    // TODO: SourceContexts!!!!!
                        nodesToAdd.Add(assignNode);

                        bodyStmtList.subnodes.InsertRange(0, nodesToAdd);
                    }
                    else
                    {
                        var si = forEachScope.SymbolInfoLoopVar;
                        var scopeWhereVarDefined = _capturedVarsTreeNodesDictionary[si.scope.ScopeNum];
                        var idRef = scopeWhereVarDefined
                            .VariablesDefinedInScope
                            .Find(var => var.SymbolInfo == si);                                                 //TODO: !!!!!!!!!!!!!!!!!!!!!!

                        var substKey = new SubstitutionKey(forEachNode.identifier.name, idRef.SyntaxTreeNodeWithVarDeclaration, forEachNode);

                        if (_substitutionsInfo.ContainsKey(substKey)) // Если нашли замену, то переменная где-то захватывалась
                        {
                            if (forEachNode.type_name == null)  //Нужно, чтобы переменная цикла создалась в этом случае в контескте с этим же именем что и была
                            {
                                forEachNode.type_name = new no_type_foreach();
                            }

                            var substDotNode = _substitutionsInfo[substKey];

                            var assignNode = new assign(substDotNode, new ident(forEachNode.identifier.name));    // TODO: SourceContexts!!!!!
                            (((statement_list)forEachNode.stmt).subnodes).Insert(0, assignNode);
                        }
                    }

                }
            }
        }
        private void SubstituteForLoopVariables()
        {
            var forScopes =
                _capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeForScope)
                                                .Select(n => (CapturedVariablesTreeNodeForScope) n.Value)
                                                .ToList();

            foreach (var forScope in forScopes)
            {
                var forNode = forScope.CorrespondingSyntaxTreeNode as for_node;
                if (forNode != null)
                {
                    CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
                    if (_generatedScopeClassesInfo.TryGetValue(forScope.ScopeIndex, out generatedClass))
                    {
                        var nodesToAdd = new List<statement>();
                        var enclosedStatementList = (statement_list) forScope.EnclosedUpperBlockScope.CorrespondingSyntaxTreeNode;
                        nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
                        if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
                        {
                            nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
                        }

                        var forNodeIndex = enclosedStatementList.subnodes.FindIndex(stmt => stmt == forNode);
                        enclosedStatementList.subnodes.InsertRange(forNodeIndex, nodesToAdd);


                        var substDotNode = new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName), new ident(forNode.loop_variable.name));
                        var assignNode = new assign(substDotNode, new ident(forNode.loop_variable.name));    // TODO: SourceContexts!!!!!
                        ((statement_list)forNode.statements).subnodes.Insert(0, assignNode); 
                    }
                    else
                    {
                        var si = forScope.SymbolInfoLoopVar;
                        var scopeWhereVarDefined = _capturedVarsTreeNodesDictionary[si.scope.ScopeNum];
                        var idRef = scopeWhereVarDefined
                            .VariablesDefinedInScope
                            .Find(var => var.SymbolInfo == si);                                                 //TODO: !!!!!!!!!!!!!!!!!!!!!!

                        var substKey = new SubstitutionKey(forNode.loop_variable.name, idRef.SyntaxTreeNodeWithVarDeclaration, forNode); 

                        if (_substitutionsInfo.ContainsKey(substKey)) // Если нашли замену, то переменная где-то захватывалась
                        {
                            forNode.create_loop_variable = true;
                            var substDotNode = _substitutionsInfo[substKey];

                            var assignNode = new assign(substDotNode, new ident(forNode.loop_variable.name));    // TODO: SourceContexts!!!!!
                            (((statement_list)forNode.statements).subnodes).Insert(0, assignNode);
                        }
                    }

                }
            }
        }
        public override void visit(ident id)
        {
            var idName = id.name.ToLower();

            var si = _visitor.context.find(idName);
            
            if (si == null)
            {
                if (InLambdaContext)
                {
                    _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
                    return;
                }
                return;
            }

            if (si.sym_info.semantic_node_type == semantic_node_type.namespace_variable ||
                si.sym_info.semantic_node_type == semantic_node_type.common_namespace_function_node ||
                si.sym_info.semantic_node_type == semantic_node_type.namespace_constant_definition ||
                si.sym_info.semantic_node_type == semantic_node_type.compiled_function_node ||
                si.sym_info.semantic_node_type == semantic_node_type.compiled_namespace_node ||
                si.sym_info.semantic_node_type == semantic_node_type.compiled_variable_definition ||
                si.sym_info.semantic_node_type == semantic_node_type.common_type_node ||
                si.sym_info.semantic_node_type == semantic_node_type.compiled_type_node ||
                si.sym_info.semantic_node_type == semantic_node_type.basic_interface_node ||
                si.sym_info.semantic_node_type == semantic_node_type.common_unit_node ||
                si.sym_info.semantic_node_type == semantic_node_type.compiled_unit_node ||
                si.sym_info.semantic_node_type == semantic_node_type.template_type)
            {
                return;
            }

            var acceptableVarType = si.sym_info.semantic_node_type == semantic_node_type.local_variable ||
                                    si.sym_info.semantic_node_type == semantic_node_type.local_block_variable ||
                                    si.sym_info.semantic_node_type == semantic_node_type.common_parameter ||
                                    si.sym_info.semantic_node_type == semantic_node_type.class_field;

            if (!(acceptableVarType) && InLambdaContext) 
            {
                _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
                return;
            }

            if (si.sym_info.semantic_node_type == semantic_node_type.class_field && InLambdaContext)
            {
                var semClassField = (class_field)si.sym_info;
                if (semClassField.polymorphic_state != polymorphic_state.ps_common)
                {
                    _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
                    return;
                }
            }

            if (si.scope == null)
            {
                return;
            }

            var scopeIndex = si.scope.ScopeNum;
            var selfWordInClass = false;

            CapturedVariablesTreeNode scope;
            if (_scopesCapturedVarsNodesDictionary.TryGetValue(scopeIndex, out scope))
            {
                var prScope = scope as CapturedVariablesTreeNodeProcedureScope;
                if (prScope != null && acceptableVarType)
                {
                    if (si.sym_info.semantic_node_type == semantic_node_type.local_variable)
                    {
                        if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && InLambdaContext)
                        {
                            _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
                        }
                    }
                    if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && InLambdaContext)
                    {
                        _visitor.AddError(new CannotCaptureNonValueParameters(_visitor.get_location(id)));
                    }
                    
                    if (idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope &&
                        _classScope != null)
                    {
                        var selfField = _classScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);

                        if (selfField == null)
                        {
                            _classScope.VariablesDefinedInScope.Add(
                                new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si));
                        }

                        selfWordInClass = true;
                    }
                    else
                    {
                        var field = prScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);

                        if (field == null)
                        {
                            prScope.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(null,
                                                                                                                 si));
                        }
                    }
                }

                var clScope = scope as CapturedVariablesTreeNodeClassScope;
                if (clScope != null && acceptableVarType)
                {
                    var field = clScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);

                    if (field == null)
                    {
                        clScope.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si));
                    }

                    if (si.access_level != access_level.al_public)
                    {
                        if (!clScope.NonPublicMembersNamesMapping.ContainsKey(idName))
                        {
                            var name = LambdaHelper.GetNameForNonPublicMember(idName);
                            var semClassField = (class_field) si.sym_info;
                            var pn = new common_property_node(name, _visitor.context._ctn, null, field_access_level.fal_public, semClassField.polymorphic_state);
                            pn.internal_property_type = _visitor.convert_strong(id).type;
                            clScope.NonPublicMembersNamesMapping.Add(idName, new Tuple<string, class_field, semantic_node>(name, semClassField, pn));
                        }
                    }
                }

                var idRef = (selfWordInClass ? _classScope : scope)
                    .VariablesDefinedInScope
                    .Find(var => var.SymbolInfo == si);

                if (idRef == null)                                     //TODO: Осторожнее переделать
                {
                    {
                        return;
                    }
                } 

                if (_currentTreeNode.CorrespondingSyntaxTreeNode != null)
                {
                    var varName = ((IVAriableDefinitionNode)idRef.SymbolInfo.sym_info).name;                      //TODO: случай параметров и полей класса!!!!!!!!!!!!!!!!!!
                    var substKey = new SubstitutionKey(varName, idRef.SyntaxTreeNodeWithVarDeclaration, _currentTreeNode.CorrespondingSyntaxTreeNode);

                    if (!_identsReferences.ContainsKey(substKey))
                    {
                        _identsReferences.Add(substKey, new List<ident>());
                    }

                    _identsReferences[substKey].Add(id);
                }

                if (InLambdaContext && scope is CapturedVariablesTreeNodeLambdaScope &&
                    scopeIndex < _currentLambdaScopeNodeStack.Peek().ScopeIndex) //TODO: Захват параметров лямбды в другой лямбде
                {
                    _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
                    return;
                }

                if (!InLambdaContext || 
                    scopeIndex >= _currentLambdaScopeNodeStack.Peek().ScopeIndex)
                {
                    return;
                }

                var stackAsList = _currentLambdaScopeNodeStack.ToList();
                stackAsList.RemoveAt(0);

                if (!_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Contains(si))
                {
                    _currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Add(si);
                    foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
                    {
                        if (!capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Contains(si))
                        {
                            capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Add(si);
                        }
                    }
                }
                if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNodeStack.Peek()))
                {
                    idRef.ReferencingLambdas.Add(_currentLambdaScopeNodeStack.Peek());
                    foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
                    {
                        if (!idRef.ReferencingLambdas.Contains(capturedVariablesTreeNodeLambdaScope))
                        {
                            idRef.ReferencingLambdas.Add(capturedVariablesTreeNodeLambdaScope);
                        }
                    }
                }
            }
        }
        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);
            }
        }
        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<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(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<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))
                        {
                            _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 VisitCapturedVar(CapturedVariablesTreeNode scope, CapturedVariablesTreeNode.CapturedSymbolInfo symbolInfo)
        {
            var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name.ToLower();
            var isSelfWordInClass = scope is CapturedVariablesTreeNodeClassScope && varName == compiler_string_consts.self_word;

            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 substKey = new SubstitutionKey(varName, symbolInfo.SyntaxTreeNodeWithVarDeclaration,
                                                       scope.CorrespondingSyntaxTreeNode);
                    if (!_substitutions.ContainsKey(substKey))
                    {
                        _substitutions.Add(substKey,
                                           new dot_node(
                                               new ident(
                                                   _capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
                                                       .GeneratedSubstitutingFieldName), new ident(varName)));
                    }

                    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),
                                            new ident(
                                                _capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
                                                    .GeneratedUpperClassFieldName));

                                    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));
                                    }
                                }
                                else
                                {
                                    dotnode = new dot_node(new ident(
                                                               _capturedVarsClassDefs[
                                                                   upperScopeWhereVarsAreCaptured.ScopeIndex]
                                                                   .GeneratedSubstitutingFieldName),
                                                           new ident(varName));
                                }

                                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)
                            {
                                var fieldType =
                                    SyntaxTreeBuilder.BuildSimpleType(upperScopeWhereVarsAreCapturedClass.type_name.name);
                                var field =
                                    SyntaxTreeBuilder.BuildClassFieldsSection(
                                        new List<ident>
                                            {
                                                new ident(
                                            _capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
                                                .GeneratedUpperClassFieldName)
                                            },
                                        new List<type_definition> {fieldType});

                                nextNodeWhereVarsAreCapturedClass.body.Add(field);

                                _capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
                                    .AssignNodeForUpperClassFieldInitialization =
                                    new assign(
                                        new dot_node(
                                            new ident(
                                                _capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
                                                    .GeneratedSubstitutingFieldName),
                                            new ident(
                                                _capturedVarsClassDefs[nextNodeWhereVarsAreCaptured.ScopeIndex]
                                                    .GeneratedUpperClassFieldName)),
                                        new ident(
                                            _capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
                                                .GeneratedSubstitutingFieldName));
                            }

                            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));
                                }

                                nodeForDotNodeCalculation = nodeForDotNodeCalculation.ParentNode;
                            }

                            if (!isSelfWordInClass)
                            {
                                dot = new dot_node(dot, new ident(varName));
                            }

                            if (!_substitutions.ContainsKey(substKey))
                            {
                                _substitutions.Add(substKey, dot);
                            }

                            upperScopeWhereVarsAreCaptured = nextNodeWhereVarsAreCaptured;
                            upperScopeWhereVarsAreCapturedClass =
                                _capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex].ClassDeclaration;
                        }
                    }

                    if (!(upperScopeWhereVarsAreCaptured == scope &&
                          upperScopeWhereVarsAreCaptured is CapturedVariablesTreeNodeClassScope))
                    {
                        if (upperScopeWhereVarsAreCaptured != scope)
                        {
                            var dotnode1 = new dot_node(
                                new ident(compiler_string_consts.self_word),
                                new ident(
                                    _capturedVarsClassDefs[upperScopeWhereVarsAreCaptured.ScopeIndex]
                                        .GeneratedUpperClassFieldName));

                            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));
                                    }

                                    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, new ident(publicProperty.Item1));
                                    }
                                    else
                                    {
                                        dotnode1 = new dot_node(dotnode1, new ident(varName));
                                    }
                                }
                                else
                                {
                                    dotnode1 = new dot_node(dotnode1, new ident(varName));
                                }
                            }
                            _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),
                                new ident(varName));

                            _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<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), new ident(propertyName ?? varName)));
                        }
                    }

                    var dotnode1 = new dot_node(
                                new ident(compiler_string_consts.self_word),
                                new ident(varName));

                    _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);
                }
            }
        }