コード例 #1
0
ファイル: SuiteStatement.cs プロジェクト: borota/JTVS
        /// <summary>
        /// Returns a new SuiteStatement which is composed of a subset of the statements in this suite statement.
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public SuiteStatement CloneSubset(JAst ast, int start, int end)
        {
            Statement[] statements = new Statement[end - start + 1];
            for (int i = start; i <= end; i++) {
                statements[i - start] = Statements[i];
            }

            var res = new SuiteStatement(statements);

            // propagate white space so we stay mostly the same...
            var itemWhiteSpace = this.GetListWhiteSpace(ast);
            var colonWhiteSpace = this.GetProceedingWhiteSpaceDefaultNull(ast);
            if (colonWhiteSpace != null) {
                ast.SetAttribute(res, NodeAttributes.PreceedingWhiteSpace, "");
            } else if (itemWhiteSpace != null) {
                // semi-colon list of statements, must end in a new line, but the original new line
                // could be multiple lines.
                ast.SetAttribute(res, NodeAttributes.ListWhiteSpace, new string[0]);
                var trailingNewLine = this.GetTrailingNewLine(ast);
                if (trailingNewLine != null) {
                    ast.SetAttribute(res, NodeAttributes.TrailingNewLine, "\r\n");
                }
            }

            if (this.IsAltForm(ast)) {
                ast.SetAttribute(res, NodeAttributes.IsAltFormValue, NodeAttributes.IsAltFormValue);
            }

            return res;
        }
コード例 #2
0
ファイル: Parser.cs プロジェクト: borota/JTVS
        //suite: simple_stmt NEWLINE | Newline INDENT stmt+ DEDENT
        private Statement ParseSuite()
        {
            if (!EatNoEof(TokenKind.Colon)) {
                // improve error handling...
                var error = ErrorStmt(_verbatim ? (_lookaheadWhiteSpace + _lookahead.Token.VerbatimImage) : null);
                NextToken();
                return error;
            }

            string colonWhiteSpace = _tokenWhiteSpace;

            TokenWithSpan cur = _lookahead;
            List<Statement> l = new List<Statement>();

            // we only read a real NewLine here because we need to adjust error reporting
            // for the interpreter.
            SuiteStatement ret;
            if (MaybeEat(TokenKind.NewLine)) {
                string suiteStartWhiteSpace = null;
                if (_verbatim) {
                    suiteStartWhiteSpace = _tokenWhiteSpace + _token.Token.VerbatimImage;
                }

                CheckSuiteEofError(cur);

                // for error reporting we track the NL tokens and report the error on
                // the last one.  This matches CJ.
                cur = _lookahead;
                while (PeekToken(TokenKind.NLToken)) {
                    cur = _lookahead;
                    NextToken();

                    if (_verbatim) {
                        suiteStartWhiteSpace += _tokenWhiteSpace + _token.Token.VerbatimImage;
                    }
                }

                if (!MaybeEat(TokenKind.Indent)) {
                    // no indent?  report the indentation error.
                    if (cur.Token.Kind == TokenKind.Dedent) {
                        ReportSyntaxError(_lookahead.Span.Start, _lookahead.Span.End, "expected an indented block", ErrorCodes.SyntaxError | ErrorCodes.IncompleteStatement);
                    } else {
                        ReportSyntaxError(cur, ErrorCodes.IndentationError);
                    }
                    return ErrorStmt(_verbatim ? (colonWhiteSpace + ':' + suiteStartWhiteSpace) : null);
                } else if (_verbatim) {
                    // indent white space belongs to the statement we're about to parse
                    _lookaheadWhiteSpace = _tokenWhiteSpace + _token.Token.VerbatimImage +_lookaheadWhiteSpace;
                }

                string trailingWhiteSpace = null;
                while (true) {
                    Statement s = ParseStmt();

                    l.Add(s);
                    if (MaybeEat(TokenKind.Dedent)) {
                        // dedent white space belongs to the statement which follows the suite
                        if (_verbatim) {
                            _lookaheadWhiteSpace = _tokenWhiteSpace + _lookaheadWhiteSpace;
                        }
                        break;
                    }
                    if (PeekToken().Kind == TokenKind.EndOfFile) {
                        ReportSyntaxError("unexpected end of file");
                        break; // error handling
                    }
                }
                ret = new SuiteStatement(l.ToArray());
                if (_verbatim) {
                    AddSecondPreceedingWhiteSpace(ret, suiteStartWhiteSpace);
                    if (trailingWhiteSpace != null) {
                        AddTrailingNewLine(ret, trailingWhiteSpace);
                    }
                }
            } else {
                //  simple_stmt NEWLINE
                //  ParseSimpleStmt takes care of the NEWLINE
                ret = new SuiteStatement(new[] { ParseSimpleStmt() });
                if (_verbatim) {
                    AddSecondPreceedingWhiteSpace(ret, "");
                }
            }

            ret.SetLoc(ret.Statements[0].StartIndex, ret.Statements[ret.Statements.Count - 1].EndIndex);
            if (_verbatim) {
                AddPreceedingWhiteSpace(ret, colonWhiteSpace);
            }
            return ret;
        }
コード例 #3
0
ファイル: Parser.cs プロジェクト: borota/JTVS
        //simple_stmt: small_stmt (';' small_stmt)* [';'] Newline
        private Statement ParseSimpleStmt()
        {
            Statement s = ParseSmallStmt();

            string newline = null;
            if (MaybeEat(TokenKind.Semicolon)) {
                var itemWhiteSpace = MakeWhiteSpaceList();
                if (itemWhiteSpace != null) {
                    itemWhiteSpace.Add(_tokenWhiteSpace);
                }

                var start = s.StartIndex;
                List<Statement> l = new List<Statement>();
                l.Add(s);
                while (true) {
                    if (MaybeEatNewLine(out newline) || MaybeEatEof()) {
                        break;
                    }

                    l.Add(ParseSmallStmt());

                    if (MaybeEatEof()) {
                        // implies a new line
                        break;
                    } else if (!MaybeEat(TokenKind.Semicolon)) {
                        EatNewLine(out newline);
                        break;
                    }
                    if (itemWhiteSpace != null) {
                        itemWhiteSpace.Add(_tokenWhiteSpace);
                    }
                }
                Statement[] stmts = l.ToArray();

                SuiteStatement ret = new SuiteStatement(stmts);
                ret.SetLoc(start, stmts[stmts.Length - 1].EndIndex);
                if (itemWhiteSpace != null) {
                    AddListWhiteSpace(ret, itemWhiteSpace.ToArray());
                }
                if (newline != null) {
                    AddTrailingNewLine(ret, newline);
                }
                return ret;
            } else if (MaybeEatEof()) {
            } else if (EatNewLine(out newline)) {
                if (_verbatim) {
                    AddTrailingNewLine(s, newline);
                }
            } else {
                // error handling, make sure we're making forward progress
                NextToken();
                if (_verbatim) {
                    AddTrailingNewLine(s, _tokenWhiteSpace + _token.Token.VerbatimImage);
                }
            }
            return s;
        }
コード例 #4
0
ファイル: Parser.cs プロジェクト: borota/JTVS
        private JAst ParseFileWorker()
        {
            StartParsing();

            List<Statement> l = new List<Statement>();

            //
            // A future statement must appear near the top of the module.
            // The only lines that can appear before a future statement are:
            // - the module docstring (if any),
            // - comments,
            // - blank lines, and
            // - other future statements.
            //

            MaybeEatNewLine();

            if (PeekToken(TokenKind.Constant)) {
                Statement s = ParseStmt();
                l.Add(s);
                _fromFutureAllowed = false;
                ExpressionStatement es = s as ExpressionStatement;
                if (es != null) {
                    ConstantExpression ce = es.Expression as ConstantExpression;
                    if (ce != null && IsString(ce)) {
                        // doc string
                        _fromFutureAllowed = true;
                    }
                }
            }

            MaybeEatNewLine();

            // from __future__
            if (_fromFutureAllowed) {
                while (PeekToken(Tokens.KeywordFromToken)) {
                    Statement s = ParseStmt();
                    l.Add(s);
                    FromImportStatement fis = s as FromImportStatement;
                    if (fis != null && !fis.IsFromFuture) {
                        // end of from __future__
                        break;
                    }
                }
            }

            // the end of from __future__ sequence
            _fromFutureAllowed = false;

            while (true) {
                if (MaybeEatEof()) break;
                if (MaybeEatNewLine()) continue;

                Statement s = ParseStmt();
                l.Add(s);
            }

            Statement[] stmts = l.ToArray();

            SuiteStatement ret = new SuiteStatement(stmts);
            AddIsAltForm(ret);
            if (_token.Token != null) {
                ret.SetLoc(0, GetEnd());
            }
            return CreateAst(ret);
        }
コード例 #5
0
ファイル: DropDownBarClient.cs プロジェクト: borota/JTVS
        /// <summary>
        /// Helper function for calculating all of the drop down entries that are available
        /// in the given suite statement.  Called to calculate both the members of top-level
        /// code and class bodies.
        /// </summary>
        private static ReadOnlyCollection<DropDownEntryInfo> CalculateEntries(SuiteStatement suite)
        {
            List<DropDownEntryInfo> newEntries = new List<DropDownEntryInfo>();

            if (suite != null) {
                foreach (Statement stmt in suite.Statements) {
                    if (stmt is ClassDefinition || stmt is FunctionDefinition) {
                        newEntries.Add(new DropDownEntryInfo(stmt));
                    }
                }
            }

            newEntries.Sort(ComparisonFunction);
            return new ReadOnlyCollection<DropDownEntryInfo>(newEntries);
        }
コード例 #6
0
ファイル: IsInstanceScope.cs プロジェクト: borota/JTVS
 public IsInstanceScope(int startIndex, SuiteStatement effectiveSuite, InterpreterScope outerScope)
     : base(null, null, outerScope)
 {
     _startIndex = _endIndex = startIndex;
     _effectiveSuite = effectiveSuite;
 }
コード例 #7
0
ファイル: MethodExtractor.cs プロジェクト: borota/JTVS
            public override bool Walk(SuiteStatement node)
            {
                foreach (var statement in node.Statements) {
                    if (statement is BreakStatement || statement is ContinueStatement) {
                        // code after here is unreachable
                        break;
                    }

                    Returns = false;
                    statement.Walk(this);
                    if (Returns) {
                        // rest of the code is unreachable...
                        break;
                    }
                }
                return false;
            }
コード例 #8
0
ファイル: SelectionTarget.cs プロジェクト: borota/JTVS
 public override Statement GetBody(JAst root)
 {
     if (_suite.Statements.Count == 0) {
         return _suite;
     }
     var ast = _suite.CloneSubset(Parents[0] as JAst, _start, _end);
     if (!_suite.IsFunctionOrClassSuite(root)) {
         ast = new SuiteStatement(new[] { ast });
     }
     return ast;
 }
コード例 #9
0
ファイル: OverviewWalker.cs プロジェクト: borota/JTVS
        public override bool Walk(SuiteStatement node)
        {
            var prevSuite = _curSuite;
            _curSuite = node;

            // recursively walk the statements in the suite
            if (node.Statements != null) {
                foreach (var innerNode in node.Statements) {
                    innerNode.Walk(this);
                }
            }

            _curSuite = prevSuite;

            // then check if we encountered an assert which added an isinstance scope.
            IsInstanceScope isInstanceScope = _scope as IsInstanceScope;
            if (isInstanceScope != null && isInstanceScope._effectiveSuite == node) {
                // pop the isinstance scope
                _scope = _scope.OuterScope;
                var declScope = _curUnit.Scope;
                // transform back into a line number and start the new statement scope on the line
                // after the suite statement.
                var lineNo = _entry.Tree.IndexToLocation(node.EndIndex).Line;

                int offset;
                if (_entry.Tree._lineLocations.Length == 0) {
                    // single line input
                    offset = 0;
                } else {
                    offset = lineNo < _entry.Tree._lineLocations.Length ? _entry.Tree._lineLocations[lineNo] : _entry.Tree._lineLocations[_entry.Tree._lineLocations.Length - 1];
                }
                var closingScope = new StatementScope(offset, declScope);
                _scope = closingScope;
                declScope.Children.Add(closingScope);
            }
            return false;
        }
コード例 #10
0
ファイル: OverviewWalker.cs プロジェクト: borota/JTVS
 public override void PostWalk(SuiteStatement node)
 {
     while (_scope is StatementScope) {
         _scope = _scope.OuterScope;
     }
     base.PostWalk(node);
 }
コード例 #11
0
ファイル: EnclosingNodeWalker.cs プロジェクト: borota/JTVS
        private bool ShouldWalkWorker(SuiteStatement node)
        {
            if (ShouldWalkWorker((Node)node)) {
                _suites.Add(node);
                foreach (var stmt in node.Statements) {
                    stmt.Walk(this);
                    if (_targetNode != null) {
                        // we have found our extracted code below this,
                        // we should insert before this statement.
                        _insertLocations[_parents[_parents.Count - 1]] = stmt.GetStartIncludingWhiteSpace(_root);
                        break;
                    }
                }
                _suites.Pop();

            }
            return false;
        }
コード例 #12
0
ファイル: EnclosingNodeWalker.cs プロジェクト: borota/JTVS
        private void PostWalkWorker(SuiteStatement node)
        {
            if (_targetNode == null && node.StartIndex <= _selectedSpan.Start && node.EndIndex >= _selectedSpan.End) {
                // figure out the range of statements we cover...
                int startIndex = 0, endIndex = node.Statements.Count - 1;
                for (int i = 0; i < node.Statements.Count; i++) {
                    if (node.Statements[i].EndIndex >= _selectedSpan.Start) {
                        startIndex = i;
                        break;
                    }
                }
                for (int i = node.Statements.Count - 1; i >= 0; i--) {
                    if (node.Statements[i].StartIndex < _selectedSpan.End) {
                        endIndex = i;
                        break;
                    }
                }
                List<SuiteStatement> followingSuites = new List<SuiteStatement>();
                for (int i = _suites.Count - 1; i >= 0; i--) {
                    if (_suites[i] == null) {
                        // we hit our marker, this is a function/class boundary
                        // We don't care about any suites which come before the marker
                        // because they live in a different scope.  We insert the marker in
                        // ShouldWalkWorker(Node node) when we have a ScopeStatement.
                        break;
                    }

                    followingSuites.Add(_suites[i]);
                }
                _targetNode = new SuiteTarget(
                    _insertLocations,
                    _parents.ToArray(),
                    node,
                    followingSuites.ToArray(),
                    _selectedSpan,
                    startIndex,
                    endIndex
                );
                _insertLocations[_parents[_parents.Count - 1]] = node.Statements.Count == 0 ?
                    node.GetStartIncludingWhiteSpace(_root) :
                    node.Statements[startIndex].GetStartIncludingWhiteSpace(_root);
            }
        }
コード例 #13
0
ファイル: EnclosingNodeWalker.cs プロジェクト: borota/JTVS
 // SuiteStatement
 public override bool Walk(SuiteStatement node)
 {
     return ShouldWalkWorker(node);
 }
コード例 #14
0
ファイル: EnclosingNodeWalker.cs プロジェクト: borota/JTVS
 public override void PostWalk(SuiteStatement node)
 {
     PostWalkWorker(node);
 }
コード例 #15
0
ファイル: OverviewWalker.cs プロジェクト: borota/JTVS
        private void PushIsInstanceScope(Node node, KeyValuePair<NameExpression, Expression>[] isInstanceNames, SuiteStatement effectiveSuite)
        {
            InterpreterScope scope;
            if (!_curUnit.Scope.TryGetNodeScope(node, out scope)) {
                if (_scope is IsInstanceScope) {
                    // Reuse the current scope
                    _curUnit.Scope.AddNodeScope(node, _scope);
                    return;
                }

                // find our parent scope, it may not be just the last entry in _scopes
                // because that can be a StatementScope and we would start a new range.
                var declScope = _scope.EnumerateTowardsGlobal.FirstOrDefault(s => !(s is StatementScope));

                scope = new IsInstanceScope(node.StartIndex, effectiveSuite, declScope);

                declScope.Children.Add(scope);
                declScope.AddNodeScope(node, scope);
                _scope = scope;
            }
        }
コード例 #16
0
ファイル: SelectionTarget.cs プロジェクト: borota/JTVS
 public SuiteTarget(Dictionary<ScopeStatement, int> insertLocations, ScopeStatement[] parents, SuiteStatement suite, SuiteStatement[] followingSuites, Span selectedSpan, int startIndex, int endIndex)
     : base(insertLocations, parents)
 {
     _suite = suite;
     _start = startIndex;
     _end = endIndex;
     _followingSuites = followingSuites;
     _selectedSpan = selectedSpan;
 }
コード例 #17
0
ファイル: ExtractedMethodCreator.cs プロジェクト: borota/JTVS
        public ExtractMethodResult GetExtractionResult(ExtractMethodRequest info)
        {
            bool isStaticMethod = false, isClassMethod = false;
            var parameters = new List<Parameter>();
            string selfParam = null;
            if (info.TargetScope is ClassDefinition) {
                var fromScope = _scopes[_scopes.Length - 1] as FunctionDefinition;
                Debug.Assert(fromScope != null);  // we don't allow extracting from classes, so we have to be coming from a function

                if (fromScope.Decorators != null) {
                    foreach (var decorator in fromScope.Decorators.Decorators) {
                        NameExpression name = decorator as NameExpression;
                        if (name != null) {
                            if (name.Name == "staticmethod") {
                                isStaticMethod = true;
                            } else if (name.Name == "classmethod") {
                                isClassMethod = true;
                            }
                        }
                    }
                }

                if (!isStaticMethod) {
                    if (fromScope.Parameters.Count > 0) {
                        selfParam = fromScope.Parameters[0].Name;
                        parameters.Add(new Parameter(selfParam, ParameterKind.Normal));
                    }
                }
            }

            foreach (var param in info.Parameters) {
                var newParam = new Parameter(param, ParameterKind.Normal);
                if (parameters.Count > 0) {
                    newParam.AddPreceedingWhiteSpace(_ast, " ");
                }
                parameters.Add(newParam);
            }

            // include any non-closed over parameters as well...
            foreach (var input in _inputVars) {
                var variableScope = input.Scope;
                var parentScope = info.TargetScope;

                // are these variables a child of the target scope so we can close over them?
                while (parentScope != null && parentScope != variableScope) {
                    parentScope = parentScope.Parent;
                }

                if (parentScope == null && input.Name != selfParam) {
                    // we can either close over or pass these in as parameters, add them to the list
                    var newParam = new Parameter(input.Name, ParameterKind.Normal);
                    if (parameters.Count > 0) {
                        newParam.AddPreceedingWhiteSpace(_ast, " ");
                    }
                    parameters.Add(newParam);
                }
            }

            var body = _target.GetBody(_ast);

            if (_outputVars.Count > 0) {
                // need to add a return statement
                Expression retValue;
                Expression[] names = new Expression[_outputVars.Count];
                int outputIndex = 0;
                foreach (var name in _outputVars) {
                    var nameExpr = new NameExpression(name.Name);
                    nameExpr.AddPreceedingWhiteSpace(_ast, " ");
                    names[outputIndex++] = nameExpr;
                }
                var tuple = new TupleExpression(false, names);
                tuple.RoundTripHasNoParenthesis(_ast);
                retValue = tuple;

                var retStmt = new ReturnStatement(retValue);
                if (body is SuiteStatement) {
                    SuiteStatement suite = (SuiteStatement)body;
                    Node.CopyLeadingWhiteSpace(_ast, suite.Statements[0], retStmt);
                    Node.CopyTrailingNewLine(_ast, suite.Statements[0], suite.Statements[suite.Statements.Count - 1]);

                    Statement[] statements = new Statement[suite.Statements.Count + 1];
                    for (int i = 0; i < suite.Statements.Count; i++) {
                        statements[i] = suite.Statements[i];
                    }
                    statements[statements.Length - 1] = retStmt;
                    body = new SuiteStatement(statements);
                } else {
                    Node.CopyLeadingWhiteSpace(_ast, body, retStmt);

                    body = new SuiteStatement(
                        new Statement[] {
                            body,
                            retStmt
                        }
                    );
                }
            }

            DecoratorStatement decorators = null;
            if (isStaticMethod) {
                decorators = new DecoratorStatement(new[] { new NameExpression("staticmethod") });
            } else if (isClassMethod) {
                decorators = new DecoratorStatement(new[] { new NameExpression("classmethod") });
            }

            var res = new FunctionDefinition(new NameExpression(info.Name), parameters.ToArray(), body, decorators);

            StringBuilder newCall = new StringBuilder();
            newCall.Append(_target.IndentationLevel);
            var method = res.ToCodeString(_ast);

            // fix up indentation...
            for (int curScope = 0; curScope < _scopes.Length; curScope++) {
                if (_scopes[curScope] == info.TargetScope) {
                    // this is our target indentation level.
                    var indentationLevel = _scopes[curScope].Body.GetIndentationLevel(_ast);
                    var lines = method.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
                    int minWhiteSpace = Int32.MaxValue;
                    for (int curLine = decorators == null ? 1 : 2; curLine < lines.Length; curLine++) {
                        var line = lines[curLine];

                        for (int i = 0; i < line.Length; i++) {
                            if (!Char.IsWhiteSpace(line[i])) {
                                minWhiteSpace = Math.Min(minWhiteSpace, i);
                                break;
                            }
                        }
                    }

                    StringBuilder newLines = new StringBuilder();
                    newLines.Append(indentationLevel);
                    newLines.Append(lines[0]);
                    if (decorators != null) {
                        newLines.Append("\r\n");
                        newLines.Append(indentationLevel);
                        newLines.Append(lines[1]);
                    }

                    // don't include a bunch of blank lines...
                    int endLine = lines.Length - 1;
                    for (; endLine >= 0 && String.IsNullOrWhiteSpace(lines[endLine]); endLine--) {
                    }

                    newLines.Append("\r\n");
                    for (int curLine = decorators == null ? 1 : 2; curLine <= endLine; curLine++) {
                        var line = lines[curLine];

                        newLines.Append(indentationLevel);
                        if (_insertTabs) {
                            newLines.Append('\t');
                        } else {
                            newLines.Append(' ', _indentSize);
                        }

                        if (line.Length > minWhiteSpace) {
                            newLines.Append(line, minWhiteSpace, line.Length - minWhiteSpace);
                        }
                        newLines.Append("\r\n");
                    }
                    newLines.Append("\r\n");
                    method = newLines.ToString();
                    break;
                }
            }

            string comma;
            if (_outputVars.Count > 0) {
                comma = "";
                foreach (var outputVar in _outputVars) {
                    newCall.Append(comma);
                    newCall.Append(outputVar.Name);
                    comma = ", ";
                }
                newCall.Append(" = ");
            } else if (_target.ContainsReturn) {
                newCall.Append("return ");
            }

            if (info.TargetScope is ClassDefinition) {
                var fromScope = _scopes[_scopes.Length - 1] as FunctionDefinition;
                Debug.Assert(fromScope != null);  // we don't allow extracting from classes, so we have to be coming from a function

                if (isStaticMethod) {
                    newCall.Append(info.TargetScope.Name);
                    newCall.Append('.');
                } else if (fromScope.Parameters.Count > 0) {
                    newCall.Append(fromScope.Parameters[0].Name);
                    newCall.Append('.');
                }
            }

            newCall.Append(info.Name);
            newCall.Append('(');

            comma = "";
            foreach (var param in parameters) {
                if (param.Name != selfParam) {
                    newCall.Append(comma);
                    newCall.Append(param.Name);
                    comma = ", ";
                }
            }

            newCall.Append(')');

            return new ExtractMethodResult(
                method,
                newCall.ToString()
            );
        }
コード例 #18
0
ファイル: SelectionTarget.cs プロジェクト: borota/JTVS
 public override IEnumerable<Statement> GetStatementsAfter(JAst root)
 {
     var ast = _suite.CloneSubset(Parents[0] as JAst, _end + 1, _suite.Statements.Count - 1);
     if (!_suite.IsFunctionOrClassSuite(root)) {
         ast = new SuiteStatement(new[] { ast });
     }
     yield return ast;
     foreach (var suite in _followingSuites) {
         foreach (var stmt in suite.Statements) {
             if (stmt.StartIndex > _selectedSpan.End) {
                 yield return stmt;
             }
         }
     }
 }
コード例 #19
0
ファイル: JLanguageInfo.cs プロジェクト: borota/JTVS
        private static string FindNodeInTree(JAst tree, SuiteStatement statement, int line)
        {
            if (statement != null) {
                foreach (var node in statement.Statements) {
                    FunctionDefinition funcDef = node as FunctionDefinition;
                    if (funcDef != null) {
                        var span = funcDef.GetSpan(tree);
                        if (span.Start.Line <= line && line <= span.End.Line) {
                            var res = FindNodeInTree(tree, funcDef.Body as SuiteStatement, line);
                            if (res != null) {
                                return funcDef.Name + "." + res;
                            }
                            return funcDef.Name;
                        }
                        continue;
                    }

                    ClassDefinition classDef = node as ClassDefinition;
                    if (classDef != null) {
                        var span = classDef.GetSpan(tree);
                        if (span.Start.Line <= line && line <= span.End.Line) {
                            var res = FindNodeInTree(tree, classDef.Body as SuiteStatement, line);
                            if (res != null) {
                                return classDef.Name + "." + res;
                            }
                            return classDef.Name;
                        }
                    }
                }
            }
            return null;
        }