public void BuildCompletionData(IEditorData Editor, string EnteredText, out string lastResultPath) { lastResultPath = null; IStatement curStmt = null; var curBlock = DResolver.SearchBlockAt(Editor.SyntaxTree, Editor.CaretLocation, out curStmt); if (curBlock == null) { return; } IEnumerable <INode> listedItems = null; // Usually shows variable members #region DotCompletion if (EnteredText == ".") { alreadyAddedModuleNameParts.Clear(); var resolveResults = DResolver.ResolveType( Editor, new ResolverContext { ScopedBlock = curBlock, ParseCache = Editor.ParseCache, ImportCache = Editor.ImportCache, ScopedStatement = curStmt } ); if (resolveResults == null) //TODO: Add after-space list creation when an unbound . (Dot) was entered which means to access the global scope { return; } /* * Note: When having entered a module name stub only (e.g. "std." or "core.") it's needed to show all packages that belong to that root namespace */ foreach (var rr in resolveResults) { lastResultPath = ResolveResult.GetResolveResultString(rr); BuildCompletionData(rr, curBlock); } } #endregion else if (EnteredText == null || EnteredText == " " || EnteredText.Length < 1 || IsIdentifierChar(EnteredText[0])) { // 1) Get current context the caret is at. ParserTrackerVariables trackVars = null; var parsedBlock = DResolver.FindCurrentCaretContext( Editor.ModuleCode, curBlock, Editor.CaretOffset, Editor.CaretLocation, out trackVars); bool CaretAfterLastParsedObject = false; if (trackVars != null && trackVars.LastParsedObject != null) { if (trackVars.LastParsedObject is IExpression) { CaretAfterLastParsedObject = Editor.CaretLocation > (trackVars.LastParsedObject as IExpression).EndLocation; } else if (trackVars.LastParsedObject is INode) { CaretAfterLastParsedObject = Editor.CaretLocation > (trackVars.LastParsedObject as INode).EndLocation; } } // 2) If in declaration and if node identifier is expected, do not show any data if (trackVars == null || (trackVars.LastParsedObject is INode && !CaretAfterLastParsedObject && trackVars.ExpectingIdentifier) || (trackVars.LastParsedObject is TokenExpression && !CaretAfterLastParsedObject && DTokens.BasicTypes[(trackVars.LastParsedObject as TokenExpression).Token] && !string.IsNullOrEmpty(EnteredText) && IsIdentifierChar(EnteredText[0])) ) { return; } var visibleMembers = DResolver.MemberTypes.All; if (trackVars.LastParsedObject is ImportStatement && !CaretAfterLastParsedObject) { visibleMembers = DResolver.MemberTypes.Imports; } else if (trackVars.LastParsedObject is NewExpression && (trackVars.IsParsingInitializer || !CaretAfterLastParsedObject)) { visibleMembers = DResolver.MemberTypes.Imports | DResolver.MemberTypes.Types; } else if (EnteredText == " ") { return; } // In class bodies, do not show variables else if (!(parsedBlock is BlockStatement) && !trackVars.IsParsingInitializer) { visibleMembers = DResolver.MemberTypes.Imports | DResolver.MemberTypes.Types | DResolver.MemberTypes.Keywords; } // In a method, parse from the method's start until the actual caret position to get an updated insight if (visibleMembers.HasFlag(DResolver.MemberTypes.Variables) && curBlock is DMethod) { if (parsedBlock is BlockStatement) { var blockStmt = parsedBlock as BlockStatement; // Insert the updated locals insight. // Do not take the caret location anymore because of the limited parsing of our code. var scopedStmt = blockStmt.SearchStatementDeeply(blockStmt.EndLocation /*Editor.CaretLocation*/); var decls = BlockStatement.GetItemHierarchy(scopedStmt, Editor.CaretLocation); foreach (var n in decls) { CompletionDataGenerator.Add(n); } } } if (visibleMembers != DResolver.MemberTypes.Imports) // Do not pass the curStmt because we already inserted all updated locals a few lines before! { listedItems = DResolver.EnumAllAvailableMembers(curBlock, null /*, curStmt*/, Editor.CaretLocation, Editor.ParseCache, visibleMembers); } //TODO: Split the keywords into such that are allowed within block statements and non-block statements // Insert typable keywords if (visibleMembers.HasFlag(DResolver.MemberTypes.Keywords)) { foreach (var kv in DTokens.Keywords) { CompletionDataGenerator.Add(kv.Key); } } #region Add module name stubs of importable modules if (visibleMembers.HasFlag(DResolver.MemberTypes.Imports)) { var nameStubs = new Dictionary <string, string>(); var availModules = new List <IAbstractSyntaxTree>(); foreach (var mod in Editor.ParseCache) { if (string.IsNullOrEmpty(mod.ModuleName)) { continue; } var parts = mod.ModuleName.Split('.'); if (!nameStubs.ContainsKey(parts[0]) && !availModules.Contains(mod)) { if (parts[0] == mod.ModuleName) { availModules.Add(mod); } else { nameStubs.Add(parts[0], GetModulePath(mod.FileName, parts.Length, 1)); } } } foreach (var kv in nameStubs) { CompletionDataGenerator.Add(kv.Key, PathOverride: kv.Value); } foreach (var mod in availModules) { CompletionDataGenerator.Add(mod.ModuleName, mod); } } #endregion } // Add all found items to the referenced list if (listedItems != null) { foreach (var i in listedItems) { if (CanItemBeShownGenerally(i) /* && dm.IsStatic*/) { CompletionDataGenerator.Add(i); } } } }
public static ISyntaxRegion FindCurrentCaretContext(IEditorData editor, out ParserTrackerVariables trackerVariables, ref IBlockNode currentScope, out IStatement currentStatement) { if (currentScope == null) { currentScope = DResolver.SearchBlockAt(editor.SyntaxTree, editor.CaretLocation, out currentStatement); } if (currentScope == null) { trackerVariables = null; currentStatement = null; return(null); } bool ParseDecl = false; int blockStart = 0; var blockStartLocation = currentScope != null ? currentScope.BlockStartLocation : editor.CaretLocation; if (currentScope is DMethod) { var block = (currentScope as DMethod).GetSubBlockAt(editor.CaretLocation); if (block != null) { blockStart = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, blockStartLocation = block.Location); } else { currentScope = currentScope.Parent as IBlockNode; return(FindCurrentCaretContext(editor, out trackerVariables, ref currentScope, out currentStatement)); } } else if (currentScope != null) { if (currentScope.BlockStartLocation.IsEmpty || (editor.CaretLocation < currentScope.BlockStartLocation && editor.CaretLocation > currentScope.Location)) { ParseDecl = true; blockStart = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, blockStartLocation = currentScope.Location); } else { blockStart = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, currentScope.BlockStartLocation); } } if (blockStart >= 0 && editor.CaretOffset - blockStart > 0) { using (var sr = new Misc.StringView(editor.ModuleCode, blockStart, editor.CaretOffset - blockStart)) { var psr = DParser.Create(sr); /* Deadly important! For correct resolution behaviour, * it is required to set the parser virtually to the blockStart position, * so that everything using the returned object is always related to * the original code file, not our code extraction! */ psr.Lexer.SetInitialLocation(blockStartLocation); ISyntaxRegion ret = null; if (currentScope == null) { ret = psr.Parse(); } else if (currentScope is DMethod) { psr.Step(); var dm = currentScope as DMethod; dm.Clear(); if ((dm.SpecialType & DMethod.MethodType.Lambda) != 0 && psr.Lexer.LookAhead.Kind != DTokens.OpenCurlyBrace) { psr.LambdaSingleStatementBody(dm); ret = dm.Body; } else { var methodRegion = DTokens.Body; if (dm.In != null && blockStartLocation == dm.In.Location) { methodRegion = DTokens.In; } if (dm.Out != null && blockStartLocation == dm.Out.Location) { methodRegion = DTokens.Out; } var newBlock = psr.BlockStatement(currentScope); ret = newBlock; switch (methodRegion) { case DTokens.Body: newBlock.EndLocation = dm.Body.EndLocation; dm.Body = newBlock; break; case DTokens.In: newBlock.EndLocation = dm.In.EndLocation; dm.In = newBlock; break; case DTokens.Out: newBlock.EndLocation = dm.Out.EndLocation; dm.Out = newBlock; break; } } } else if (currentScope is DModule) { ret = psr.Root(); } else { psr.Step(); if (ParseDecl) { var ret2 = psr.Declaration(currentScope); if (ret2 != null && ret2.Length > 0) { ret = ret2[0]; } } else if (currentScope is DClassLike) { var t = new DClassLike((currentScope as DClassLike).ClassType); t.AssignFrom(currentScope); t.Clear(); psr.ClassBody(t); ret = t; } else if (currentScope is DEnum) { var t = new DEnum(); t.AssignFrom(currentScope); t.Clear(); psr.EnumBody(t); ret = t; } } currentScope = DResolver.SearchBlockAt(currentScope, psr.Lexer.CurrentToken != null ? psr.Lexer.CurrentToken.EndLocation : editor.CaretLocation, out currentStatement); trackerVariables = psr.TrackerVariables; return(ret); } } trackerVariables = null; currentStatement = null; return(null); }
/// <returns>Either CurrentScope, a BlockStatement object that is associated with the parent method or a complete new DModule object</returns> public static object FindCurrentCaretContext(string code, IBlockNode CurrentScope, int caretOffset, CodeLocation caretLocation, out ParserTrackerVariables TrackerVariables) { bool ParseDecl = false; int blockStart = 0; var blockStartLocation = CurrentScope.BlockStartLocation; if (CurrentScope is DMethod) { var block = (CurrentScope as DMethod).GetSubBlockAt(caretLocation); if (block != null) { blockStart = DocumentHelper.LocationToOffset(code, blockStartLocation = block.Location); } else { return(FindCurrentCaretContext(code, CurrentScope.Parent as IBlockNode, caretOffset, caretLocation, out TrackerVariables)); } } else if (CurrentScope != null) { if (CurrentScope.BlockStartLocation.IsEmpty || caretLocation < CurrentScope.BlockStartLocation && caretLocation > CurrentScope.Location) { ParseDecl = true; blockStart = DocumentHelper.LocationToOffset(code, blockStartLocation = CurrentScope.Location); } else { blockStart = DocumentHelper.LocationToOffset(code, CurrentScope.BlockStartLocation); } } if (blockStart >= 0 && caretOffset - blockStart > 0) { var codeToParse = code.Substring(blockStart, caretOffset - blockStart); var sr = new StringReader(codeToParse); var psr = DParser.Create(sr); /* Deadly important! For correct resolution behaviour, * it is required to set the parser virtually to the blockStart position, * so that everything using the returned object is always related to * the original code file, not our code extraction! */ psr.Lexer.SetInitialLocation(blockStartLocation); object ret = null; if (CurrentScope == null || CurrentScope is IAbstractSyntaxTree) { ret = psr.Parse(); } else if (CurrentScope is DMethod) { psr.Step(); ret = psr.BlockStatement(CurrentScope); } else if (CurrentScope is DModule) { ret = psr.Root(); } else { psr.Step(); if (ParseDecl) { var ret2 = psr.Declaration(CurrentScope); if (ret2 != null && ret2.Length > 0) { ret = ret2[0]; } } else { DBlockNode bn = null; if (CurrentScope is DClassLike) { var t = new DClassLike((CurrentScope as DClassLike).ClassType); t.AssignFrom(CurrentScope); bn = t; } else if (CurrentScope is DEnum) { var t = new DEnum(); t.AssignFrom(CurrentScope); bn = t; } bn.Clear(); psr.ClassBody(bn); ret = bn; } } TrackerVariables = psr.TrackerVariables; sr.Close(); return(ret); } TrackerVariables = null; return(null); }
/// <summary> /// Reparses the given method's fucntion body until the cursor position, /// searches the last occurring method call or template instantiation, /// counts its already typed arguments /// and returns a wrapper containing all the information. /// </summary> public static ArgumentsResolutionResult ResolveArgumentContext( IEditorData Editor, ResolverContextStack ctxt) { ParserTrackerVariables trackVars = null; IStatement curStmt = null; IExpression lastParamExpression = null; // Get the currently scoped block var curBlock = DResolver.SearchBlockAt(Editor.SyntaxTree, Editor.CaretLocation, out curStmt); if (curBlock == null) { return(null); } // Get an updated abstract view on the module's code var parsedStmtBlock = CtrlSpaceCompletionProvider.FindCurrentCaretContext( Editor.ModuleCode, curBlock, Editor.CaretOffset, Editor.CaretLocation, out trackVars) as StatementContainingStatement; if (parsedStmtBlock == null) { return(null); } // Search the returned statement block (i.e. function body) for the current statement var exStmt = BlockStatement.SearchBlockStatement(parsedStmtBlock, Editor.CaretLocation) as IExpressionContainingStatement; lastParamExpression = ExpressionHelper.SearchForMethodCallsOrTemplateInstances(exStmt, Editor.CaretLocation); if (lastParamExpression == null) { // Give it a last chance by handling the lastly parsed object // - which is a TemplateInstanceExpression in quite all cases lastParamExpression = trackVars.LastParsedObject as IExpression; } /* * Then handle the lastly found expression regarding the following points: * * 1) foo( -- normal arguments only * 2) foo!(...)( -- normal arguments + template args * 3) foo!( -- template args only * 4) new myclass( -- ctor call * 5) new myclass!( -- ditto * 6) new myclass!(...)( * 7) mystruct( -- opCall call */ var res = new ArgumentsResolutionResult() { ParsedExpression = lastParamExpression }; // 1), 2) if (lastParamExpression is PostfixExpression_MethodCall) { res.IsMethodArguments = true; var call = (PostfixExpression_MethodCall)lastParamExpression; res.MethodIdentifier = call.PostfixForeExpression; res.ResolvedTypesOrMethods = Evaluation.TryGetUnfilteredMethodOverloads(call.PostfixForeExpression, ctxt, call); if (call.Arguments != null) { int i = 0; foreach (var arg in call.Arguments) { if (Editor.CaretLocation >= arg.Location && Editor.CaretLocation <= arg.EndLocation) { res.CurrentlyTypedArgumentIndex = i; break; } i++; } } } // 3) else if (lastParamExpression is TemplateInstanceExpression) { var templ = (TemplateInstanceExpression)lastParamExpression; res.IsTemplateInstanceArguments = true; res.MethodIdentifier = templ; res.ResolvedTypesOrMethods = Evaluation.GetOverloads(templ, ctxt, null, false); if (templ.Arguments != null) { int i = 0; foreach (var arg in templ.Arguments) { if (Editor.CaretLocation >= arg.Location && Editor.CaretLocation <= arg.EndLocation) { res.CurrentlyTypedArgumentIndex = i; break; } i++; } } } else if (lastParamExpression is PostfixExpression_Access) { var acc = (PostfixExpression_Access)lastParamExpression; res.MethodIdentifier = acc.PostfixForeExpression; res.ResolvedTypesOrMethods = Evaluation.TryGetUnfilteredMethodOverloads(acc.PostfixForeExpression, ctxt, acc); if (res.ResolvedTypesOrMethods == null) { return(res); } if (acc.AccessExpression is NewExpression) { CalculateCurrentArgument(acc.AccessExpression as NewExpression, res, Editor.CaretLocation, ctxt, res.ResolvedTypesOrMethods); } } else if (lastParamExpression is NewExpression) { HandleNewExpression((NewExpression)lastParamExpression, res, Editor, ctxt, curBlock); } /* * alias int function(int a, bool b) myDeleg; * alias myDeleg myDeleg2; * * myDeleg dg; * * dg( -- it's not needed to have myDeleg but the base type for what it stands for * * ISSUE: * myDeleg( -- not allowed though * myDeleg2( -- allowed neither! */ if (res.ResolvedTypesOrMethods != null) { res.ResolvedTypesOrMethods = DResolver.StripAliasSymbols(res.ResolvedTypesOrMethods); } return(res); }
public static AbstractCompletionProvider Create(ICompletionDataGenerator dataGen, IEditorData Editor, string EnteredText) { if (PropertyAttributeCompletionProvider.CompletesEnteredText(EnteredText)) { return(new PropertyAttributeCompletionProvider(dataGen)); } ParserTrackerVariables trackVars = null; IStatement curStmt = null; var curBlock = DResolver.SearchBlockAt(Editor.SyntaxTree, Editor.CaretLocation, out curStmt); if (curBlock == null) { return(null); } var parsedBlock = CtrlSpaceCompletionProvider.FindCurrentCaretContext( Editor.ModuleCode, curBlock, Editor.CaretOffset, Editor.CaretLocation, out trackVars); if (trackVars != null) { if (trackVars.LastParsedObject is PostfixExpression_Access) { return new MemberCompletionProvider(dataGen) { AccessExpression = trackVars.LastParsedObject as PostfixExpression_Access, ScopedBlock = curBlock, ScopedStatement = curStmt } } ; if (trackVars.ExpectingIdentifier) { if (trackVars.LastParsedObject is DAttribute) { return new AttributeCompletionProvider(dataGen) { Attribute = trackVars.LastParsedObject as DAttribute } } ; else if (trackVars.LastParsedObject is ScopeGuardStatement) { return new ScopeAttributeCompletionProvider(dataGen) { //ScopeStmt = trackVars.LastParsedObject as ScopeGuardStatement } } ; else if (trackVars.LastParsedObject is PragmaStatement) { return new AttributeCompletionProvider(dataGen) { Attribute = (trackVars.LastParsedObject as PragmaStatement).Pragma } } ; else if (trackVars.LastParsedObject is TraitsExpression) { return new TraitsExpressionCompletionProvider(dataGen) { //TraitsExpr=trackVars.LastParsedObject as TraitsExpression } } ; else if (trackVars.LastParsedObject is ImportStatement.Import) { return(new ImportStatementCompletionProvider(dataGen, (ImportStatement.Import)trackVars.LastParsedObject)); } else if (trackVars.LastParsedObject is ImportStatement.ImportBindings) { return(new ImportStatementCompletionProvider(dataGen, (ImportStatement.ImportBindings)trackVars.LastParsedObject)); } } if (EnteredText == "(") { return(null); } } return(new CtrlSpaceCompletionProvider(dataGen) { trackVars = trackVars, curBlock = curBlock, parsedBlock = parsedBlock }); }