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);
        }
示例#4
0
        /// <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
            });
        }