/// <summary> /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative) /// that is beneath the caret location. /// /// Used for code completion/symbol resolution. /// Mind the extra options that might be passed via the Options parameter. /// </summary> /// <param name="ctxt">Can be null</param> public static ISyntaxRegion GetScopedCodeObject(IEditorData editor, ResolverContextStack ctxt = null, AstReparseOptions Options = 0) { if (ctxt == null) { ctxt = ResolverContextStack.Create(editor); } var code = editor.ModuleCode; int start = 0; var startLocation = CodeLocation.Empty; bool IsExpression = false; if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement) { var exprs = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions; IExpression targetExpr = null; if (exprs != null) { foreach (var ex in exprs) { if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation, true)) != ex) { break; } } } if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation) { startLocation = targetExpr.Location; start = DocumentHelper.LocationToOffset(editor.ModuleCode, startLocation); IsExpression = true; } } if (!IsExpression) { // First check if caret is inside a comment/string etc. int lastStart = -1; int lastEnd = -1; var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd); // Return if comment etc. found if (caretContext != TokenContext.None) { return(null); } start = CaretContextAnalyzer.SearchExpressionStart(code, editor.CaretOffset - 1, (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0); startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start); } if (start < 0 || editor.CaretOffset <= start) { return(null); } var expressionCode = code.Substring(start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start); var parser = DParser.Create(new StringReader(expressionCode)); parser.Lexer.SetInitialLocation(startLocation); parser.Step(); if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier) { return(parser.IdentifierList()); } else if (IsExpression || parser.IsAssignExpression()) { if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(parser.AssignExpression()); } else { return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation, Options.HasFlag(AstReparseOptions.WatchForParamExpressions))); } } else { return(parser.Type()); } }
/// <summary> /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative) /// that is beneath the caret location. /// /// Used for code completion/symbol resolution. /// Mind the extra options that might be passed via the Options parameter. /// </summary> /// <param name="ctxt">Can be null</param> public static ISyntaxRegion GetScopedCodeObject(IEditorData editor, AstReparseOptions Options = AstReparseOptions.AlsoParseBeyondCaret, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var code = editor.ModuleCode; int start = 0; var startLocation = CodeLocation.Empty; bool IsExpression = false; if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement) { var exprs = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions; IExpression targetExpr = null; if (exprs != null) { foreach (var ex in exprs) { if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation)) != ex) { break; } } } if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation) { startLocation = targetExpr.Location; start = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, startLocation); IsExpression = true; } } if (!IsExpression) { // First check if caret is inside a comment/string etc. int lastStart = 0; int lastEnd = 0; if ((Options & AstReparseOptions.DontCheckForCommentsOrStringSurrounding) == 0) { var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd); // Return if comment etc. found if (caretContext != TokenContext.None) { return(null); } } // Could be somewhere in an ITypeDeclaration.. if (editor.CaretOffset < 0 || editor.CaretOffset >= code.Length) { return(null); } if (Lexer.IsIdentifierPart(code[editor.CaretOffset])) { start = editor.CaretOffset; } else if (editor.CaretOffset > 0 && Lexer.IsIdentifierPart(code[editor.CaretOffset - 1])) { start = editor.CaretOffset - 1; } start = CaretContextAnalyzer.SearchExpressionStart(code, start, (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0); startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start); } if (start < 0 || editor.CaretOffset < start) { return(null); } var sv = new StringView(code, start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start); var parser = DParser.Create(sv); parser.Lexer.SetInitialLocation(startLocation); parser.Step(); ITypeDeclaration td; if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier) { td = parser.IdentifierList(); } else if (IsExpression || parser.IsAssignExpression()) { if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(parser.AssignExpression()); } else { return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation)); } } else { td = parser.Type(); } if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(td); } while (td != null && td.InnerDeclaration != null && editor.CaretLocation <= td.InnerDeclaration.EndLocation) { td = td.InnerDeclaration; } return(td); }