コード例 #1
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Performs a parsing operation using the parameters specified in the supplied <see cref="IParseRequest"/>
        /// and returns the resulting parse data.
        /// </summary>
        /// <param name="request">The <see cref="IParseRequest"/> that contains data about the requested parsing operation.</param>
        /// <returns>An <see cref="IParseData"/> that is the result of the parsing operation.</returns>
        /// <remarks>
        /// A <see cref="IParseRequestDispatcher"/> typically calls this method when a queued parse request is ready to be processed.
        /// </remarks>
        public override IParseData Parse(IParseRequest request)
        {
            SimpleParseData parseData = new SimpleParseData();

            //
            // NOTE: Make sure that you've set up an ambient parse request dispatcher for your application
            //   (see documentation on 'Parse Requests and Dispatchers') so that this parser is called in
            //   a worker thread as the editor is updated
            //

            // Most parsers will use the request.TextBufferReader property in some fashion to scan through
            //   text and not a snapshot directly... in this basic sample though, we're going to use the
            //   tokenization provided by the snapshot's reader so we can only proceed if there is a
            //   snapshot passed to us
            if (request.Snapshot != null)
            {
                ITextSnapshotReader reader = request.Snapshot.GetReader(0);

                bool isFunctionStart = false;
                while (!reader.IsAtSnapshotEnd)
                {
                    IToken token = reader.ReadToken();
                    if (token != null)
                    {
                        switch (token.Key)
                        {
                        case "Keyword":
                            // If a function token, mark that this is a function start... the next identifier should be the function name
                            isFunctionStart = (reader.Snapshot.GetSubstring(token.TextRange) == "function");
                            break;

                        case "Identifier":
                            // If this is the function name...
                            if (isFunctionStart)
                            {
                                parseData.Functions.Add(new TextSnapshotRange(reader.Snapshot, token.TextRange));
                                isFunctionStart = false;
                            }
                            break;

                        case "Whitespace":
                            // Ignore
                            break;

                        default:
                            // Flag as no longer in a function start
                            isFunctionStart = false;
                            break;
                        }
                    }
                }
            }

            return(parseData);
        }
コード例 #2
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Performs a parsing operation using the parameters specified in the supplied <see cref="IParseRequest"/>
        /// and returns the resulting parse data.
        /// </summary>
        /// <param name="request">The <see cref="IParseRequest"/> that contains data about the requested parsing operation.</param>
        /// <returns>An <see cref="IParseData"/> that is the result of the parsing operation.</returns>
        /// <remarks>
        /// A <see cref="IParseRequestDispatcher"/> typically calls this method when a queued parse request is ready to be processed.
        /// </remarks>
        public override IParseData Parse(IParseRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Create parse data
            ParentParseData parseData = new ParentParseData();

            parseData.Snapshot = request.Snapshot;

            // Initialize generated text
            StringBuilder generatedText = new StringBuilder();

            generatedText.Append("using System;\n");
            generatedText.Append("using System.Collections.Generic;\n\n");
            generatedText.Append("using System.Linq;\n\n");
            generatedText.Append("[EditorBrowsable(EditorBrowsableState.Never)]\n");
            generatedText.Append("class __Generated {\n");
            generatedText.Append("\t[EditorBrowsable(EditorBrowsableState.Never)]\n");
            generatedText.Append("\tvoid __WriteOutput() {\n");

            ITextSnapshotReader sourceReader = request.Snapshot.GetReader(0);
            int  lastDelimiterOffset         = 0;
            bool lastDelimiterWasStart       = false;

            while (!sourceReader.IsAtSnapshotEnd)
            {
                IToken token = sourceReader.ReadToken();
                if (token != null)
                {
                    switch (token.Id)
                    {
                    case ParentTokenId.ChildCodeBlockStart:
                    case ParentTokenId.ChildOutputBlockStart:
                        if (token.StartOffset - lastDelimiterOffset > 0)
                        {
                            // Append generated text
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\tResponse.Write(@\"");
                            generatedText.Append(text.Replace("\"", "\"\""));
                            generatedText.Append("\");\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = true;
                        break;

                    case ParentTokenId.ChildCodeBlockEnd:
                        if ((lastDelimiterWasStart) && (token.StartOffset - lastDelimiterOffset > 0))
                        {
                            // Get the text between the delimiters
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\t");

                            // Add a mapping
                            parseData.TextRangeMappings.Add(Tuple.Create(new TextRange(lastDelimiterOffset, token.StartOffset), TextRange.FromSpan(generatedText.Length, text.Length)));

                            // Append the text directly
                            generatedText.Append(text);
                            generatedText.Append("\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = false;
                        break;

                    case ParentTokenId.ChildOutputBlockEnd:
                        if ((lastDelimiterWasStart) && (token.StartOffset - lastDelimiterOffset > 0))
                        {
                            // Get the text between the delimiters and append a Response.Write
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\tResponse.Write(");

                            // Add a mapping
                            parseData.TextRangeMappings.Add(Tuple.Create(new TextRange(lastDelimiterOffset, token.StartOffset), TextRange.FromSpan(generatedText.Length, text.Length)));

                            // Append the text directly
                            generatedText.Append(text);
                            generatedText.Append(");\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = false;
                        break;
                    }
                }
            }

            if (lastDelimiterOffset < sourceReader.Snapshot.Length)
            {
                // Append generated text
                string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, sourceReader.Snapshot.Length), LineTerminator.Newline);
                generatedText.Append("\t\tResponse.Write(@\"");
                generatedText.Append(text.Replace("\"", "\"\""));
                generatedText.Append("\");\n");
            }

            // Store the generated text
            generatedText.Append("\t}\n");
            generatedText.Append("}\n");

            // Get parse data for the translated code
            CodeDocument generatedDocument = new CodeDocument();

            generatedDocument.Language = childLanguage;
            generatedDocument.SetText(generatedText.ToString());

            // Get a reader
            ITextBufferReader generatedReader = generatedDocument.CurrentSnapshot.GetReader(0).BufferReader;

            // Create a request
            ParseRequest generatedRequest = new ParseRequest(Guid.NewGuid().ToString(), generatedReader, childParser, generatedDocument);

            generatedRequest.Snapshot = generatedDocument.CurrentSnapshot;

            // Parse
            generatedDocument.ParseData  = childParser.Parse(generatedRequest);
            parseData.GeneratedParseData = generatedDocument.ParseData as ILLParseData;

            return(parseData);
        }
コード例 #3
0
        /// <summary>
        /// Initializes a new instance of the <c>JavascriptOutliningSource</c> class.
        /// </summary>
        /// <param name="snapshot">The <see cref="ITextSnapshot"/> to use for this outlining source.</param>
        public JavascriptOutliningSource(ITextSnapshot snapshot) : base(snapshot)
        {
            int    curlyBraceStartOffset = -1;
            int    curlyBraceLevel       = 0;
            int    commentStartOffset    = -1;
            IToken token;

            // Get a text snapshot reader so that we can read tokens
            ITextSnapshotReader reader = snapshot.GetReader(0);

            // Read through the entire snapshot
            while (!reader.IsAtSnapshotEnd)
            {
                // Get the next token
                token = reader.ReadToken();
                if (token != null)
                {
                    switch (token.Key)
                    {
                    case "MultiLineCommentStartDelimiter":
                        // A multi-line comment is starting... save its start offset
                        if (commentStartOffset == -1)
                        {
                            commentStartOffset = token.StartOffset;
                        }
                        break;

                    case "MultiLineCommentEndDelimiter":
                        // A multi-line comment is ending... add its range to the outlining source
                        if (commentStartOffset != -1)
                        {
                            this.AddNode(new TextRange(commentStartOffset, token.EndOffset), multiLineCommentDefinition);
                            commentStartOffset = -1;
                        }
                        break;

                    case "OpenCurlyBrace":
                        // An open curly brace... save its start offset if it's a top-level brace
                        if (curlyBraceLevel++ == 0)
                        {
                            if (curlyBraceStartOffset == -1)
                            {
                                curlyBraceStartOffset = token.StartOffset;
                            }
                        }
                        break;

                    case "CloseCurlyBrace":
                        // A close curly brace... add its range to the outlining source if it's a top-level brace
                        if (curlyBraceLevel > 0)
                        {
                            curlyBraceLevel--;
                            if (curlyBraceLevel == 0)
                            {
                                this.AddNode(new TextRange(curlyBraceStartOffset, token.EndOffset), curlyBraceDefinition);
                                curlyBraceStartOffset = -1;
                            }
                        }
                        break;
                    }
                }
                else
                {
                    break;
                }
            }

            // If there are any "open" nodes (never found a matching end), add them too
            if (commentStartOffset != -1)
            {
                this.AddOpenNode(commentStartOffset, multiLineCommentDefinition);
            }
            if (curlyBraceStartOffset != -1)
            {
                this.AddOpenNode(curlyBraceStartOffset, curlyBraceDefinition);
            }
        }
コード例 #4
0
        /// <summary>
        /// Examines the snapshot text to determine more detail about the context.
        /// </summary>
        /// <param name="context">The <see cref="SimpleContext"/> to update.</param>
        /// <param name="includeArgumentInfo">Whether to populate the argument-related context properties, for use with parameter info.</param>
        private static void UpdateFromSnapshotText(SimpleContext context, bool includeArgumentInfo)
        {
            // Get the snapshot offset
            TextSnapshotOffset snapshotOffset = context.SnapshotOffset;

            // Create a default initialization range
            context.InitializationSnapshotRange = new TextSnapshotRange(snapshotOffset);

            // Get a snapshot reader
            ITextSnapshotReader reader = snapshotOffset.Snapshot.GetReader(snapshotOffset.Offset);

            if (reader == null)
            {
                return;
            }

            IToken token = reader.ReadToken();

            if (token != null)
            {
                // If the current token is a comment, flag no context
                switch (token.Id)
                {
                case SimpleTokenId.MultiLineCommentEndDelimiter:
                case SimpleTokenId.MultiLineCommentLineTerminator:
                case SimpleTokenId.MultiLineCommentStartDelimiter:
                case SimpleTokenId.MultiLineCommentText:
                case SimpleTokenId.SingleLineCommentEndDelimiter:
                case SimpleTokenId.SingleLineCommentStartDelimiter:
                case SimpleTokenId.SingleLineCommentText:
                    context.Type = SimpleContextType.None;
                    return;
                }
            }

            // If we are in a function declaration block...
            if (context.Type == SimpleContextType.FunctionDeclarationBlock)
            {
                // Get the AST
                ICodeDocument document = snapshotOffset.Snapshot.Document as ICodeDocument;
                if (document == null)
                {
                    return;
                }
                ILLParseData parseData = document.ParseData as ILLParseData;
                if (parseData == null)
                {
                    return;
                }
                CompilationUnit compilationUnit = parseData.Ast as CompilationUnit;
                if ((compilationUnit == null) || (!compilationUnit.HasMembers))
                {
                    return;
                }

                // If argument data should be scanned...
                if (includeArgumentInfo)
                {
                    // Scan backward to look for argument data
                    reader.Offset = snapshotOffset.Offset;
                    reader.GoToCurrentTokenStart();
                    var startOffset = reader.Offset;
                    token = reader.ReadTokenReverse();
                    while (token != null)
                    {
                        // Quit if we look behind too far (for performance reasons) - 500 is arbitrary number and could be tweaked
                        if ((!context.ArgumentIndex.HasValue) && (startOffset - reader.Offset > 500))
                        {
                            return;
                        }

                        switch (token.Id)
                        {
                        case SimpleTokenId.CloseParenthesis:
                            // Skip over ( ... ) pair
                            if (!reader.GoToPreviousMatchingTokenById(SimpleTokenId.CloseParenthesis, SimpleTokenId.OpenParenthesis))
                            {
                                return;
                            }
                            break;

                        case SimpleTokenId.Comma:
                            // Update the context data
                            if (context.ArgumentIndex.HasValue)
                            {
                                context.ArgumentIndex++;
                            }
                            else
                            {
                                context.ArgumentIndex          = 1;
                                context.ArgumentSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.EndOffset);
                            }
                            break;

                        case SimpleTokenId.OpenParenthesis:
                            // Update the context data
                            context.ArgumentListSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.EndOffset);
                            if (!context.ArgumentIndex.HasValue)
                            {
                                context.ArgumentIndex          = 0;
                                context.ArgumentSnapshotOffset = context.ArgumentListSnapshotOffset;
                            }

                            // Go to the previous token
                            reader.GoToPreviousToken();
                            token = reader.Token;
                            if ((token != null) && (token.Id == SimpleTokenId.Identifier))
                            {
                                // Loop through the AST nodes to ensure that the identifier text matches a declared function name
                                string functionName = reader.TokenText;
                                foreach (FunctionDeclaration functionAstNode in compilationUnit.Members)
                                {
                                    // If the name matches the function's name...
                                    if (functionAstNode.Name == functionName)
                                    {
                                        // Update the target function
                                        context.TargetFunction = functionAstNode;
                                        break;
                                    }
                                }
                            }
                            return;

                        default:
                            // Quit if any tokens are found that aren't allowed in invocations
                            if (!IsTokenAllowedInInvocation(token.Id))
                            {
                                return;
                            }
                            else
                            {
                                break;
                            }
                        }

                        // Move back a token
                        token = reader.ReadTokenReverse();
                    }
                }
                else
                {
                    // If the current token is an identifier...
                    if ((token != null) && (token.Id == SimpleTokenId.Identifier))
                    {
                        // Store the identifier snapshot range in case this is a function reference token
                        TextSnapshotRange identifierSnapshotRange = new TextSnapshotRange(reader.Snapshot, token.TextRange);

                        // Next, check to ensure the next non-whitespace token is a '('
                        token = reader.ReadToken();
                        while (!reader.IsAtSnapshotEnd)
                        {
                            if (token != null)
                            {
                                switch (token.Id)
                                {
                                case SimpleTokenId.Whitespace:
                                    // Continue
                                    break;

                                case SimpleTokenId.OpenParenthesis: {
                                    // Loop through the AST nodes to ensure that the identifier text matches a declared function name
                                    foreach (FunctionDeclaration functionAstNode in compilationUnit.Members)
                                    {
                                        // If the name matches the function's name...
                                        if (functionAstNode.Name == identifierSnapshotRange.Text)
                                        {
                                            // Update the context type
                                            context.Type = SimpleContextType.FunctionReference;
                                            context.InitializationSnapshotRange = identifierSnapshotRange;
                                            context.TargetFunction = functionAstNode;
                                            break;
                                        }
                                    }
                                    return;
                                }

                                default:
                                    // Quit
                                    return;
                                }
                            }

                            // Advance
                            token = reader.ReadToken();
                        }
                    }
                }
            }
        }