Example #1
0
 public TokenRegion(SnapshotPoint start, SnapshotPoint end, DafnyTokenKind kind)
 {
     Start = start;
     End   = end;
     Kind  = kind;
 }
Example #2
0
 public DafnyTokenTag(DafnyTokenKind kind, string fixedHoverText, Microsoft.Dafny.IVariable variable = null)
 {
     this.Kind           = kind;
     this.FixedHoverText = fixedHoverText;
     this.Variable       = variable;
 }
Example #3
0
        private static SnapshotPoint Scan(string txt, SnapshotPoint start, List <TokenRegion> newRegions, ITextSnapshot newSnapshot)
        {
            int           longCommentDepth     = 0;
            SnapshotPoint commentStart         = new SnapshotPoint();
            SnapshotPoint commentEndAsWeKnowIt = new SnapshotPoint(); // used only when longCommentDepth != 0
            int           N    = txt.Length;
            bool          done = false;

            while (!done)
            {
                N = txt.Length; // length of the current buffer
                int cur = 0;    // offset into the current buffer
                if (longCommentDepth != 0)
                {
                    ScanForEndOfComment(txt, ref longCommentDepth, ref cur);
                    if (longCommentDepth == 0)
                    {
                        // we just finished parsing a long comment
                        newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, start + cur), DafnyTokenKind.Comment));
                    }
                    else
                    {
                        // we're still parsing the long comment
                        Contract.Assert(cur == txt.Length);
                        commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, start + cur);
                        goto OUTER_CONTINUE;
                    }
                }
                // repeatedly get the remaining tokens from this buffer
                int end; // offset into the current buffer
                for (; ; cur = end)
                {
                    // advance to the first character of a keyword or token
                    DafnyTokenKind ty = DafnyTokenKind.Keyword;
                    for (; ; cur++)
                    {
                        if (N <= cur)
                        {
                            // we've looked at everything in this buffer
                            goto OUTER_CONTINUE;
                        }
                        char ch = txt[cur];
                        if ('a' <= ch && ch <= 'z')
                        {
                            break;
                        }
                        if ('A' <= ch && ch <= 'Z')
                        {
                            break;
                        }
                        if ('0' <= ch && ch <= '9')
                        {
                            ty = DafnyTokenKind.Number; break;
                        }
                        if (ch == '_' || ch == '?' || ch == '\\')
                        {
                            break;                            // parts of identifiers
                        }
                        if (ch == '\'')
                        {
                            ty = DafnyTokenKind.Char; break;
                        }                                         // part character literal or identifier
                        if (ch == '"')
                        {
                            ty = DafnyTokenKind.String; break;
                        }
                        if (ch == '/')
                        {
                            ty = DafnyTokenKind.Comment; break;
                        }
                    }

                    // advance to the end of the token
                    end = cur + 1; // offset into the current buffer
                    // first investigate if this is really a character literal
                    if (ty == DafnyTokenKind.Char)
                    {
                        ty = DafnyTokenKind.Keyword;
                        // we've seen a starting single-quote already
                        if (cur + 3 <= N && txt[cur + 2] == '\'')
                        {
                            // Look for a simple character literal, like 'a'
                            char cx = txt[cur + 1];
                            if (cx != '\'' && cx != '\\' && cx != '\n' && cx != '\r')
                            {
                                if (cur + 3 == N)
                                {
                                    ty  = DafnyTokenKind.Char;
                                    end = cur + 3;
                                }
                                else
                                {
                                    // check if the next character is an identifier character, because then what we've seen was
                                    // really just part of that identifier
                                    cx = txt[cur + 3];
                                    if ('a' <= cx && cx <= 'z')
                                    {
                                    }
                                    else if ('A' <= cx && cx <= 'Z')
                                    {
                                    }
                                    else if ('0' <= cx && cx <= '9')
                                    {
                                    }
                                    else if (cx == '\'' || cx == '_' || cx == '?' || cx == '\\')
                                    {
                                    }
                                    else
                                    {
                                        ty  = DafnyTokenKind.Char;
                                        end = cur + 3;
                                    }
                                }
                            }
                        }
                        else if (cur + 4 <= N && txt[cur + 1] == '\\' && txt[cur + 3] == '\'')
                        {
                            // Look for an escaped character literal, like '\n' (note, a \ cannot be part of an identifier)
                            char cx = txt[cur + 2];
                            if (cx == '\'' || cx == '\"' || cx == '\\' || cx == '0' || cx == 'n' || cx == 'r' || cx == 't')
                            {
                                ty  = DafnyTokenKind.Char;
                                end = cur + 4;
                            }
                        }
                        else if (cur + 8 <= N && txt[cur + 1] == '\\' && txt[cur + 2] == 'u' && txt[cur + 7] == '\'')
                        {
                            // Look for a unicode character literal, like '\u40fE' (note, a \ cannot be part of an identifier)
                            var numberOfHexDigits = 0;
                            for (int i = 3; i < 7; i++)
                            {
                                char cx = txt[cur + i];
                                if (('0' <= cx && cx <= '9') || ('a' <= cx && cx <= 'f') || ('A' <= cx && cx <= 'F'))
                                {
                                    numberOfHexDigits++;
                                }
                            }
                            if (numberOfHexDigits == 4)
                            {
                                ty  = DafnyTokenKind.Char;
                                end = cur + 8;
                            }
                        }
                    }

                    if (ty == DafnyTokenKind.Number)
                    {
                        // scan the rest of this number
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('0' <= ch && ch <= '9')
                            {
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.Char)
                    {
                        // we already did the work above
                    }
                    else if (ty == DafnyTokenKind.String)
                    {
                        // scan the rest of this string, but not past the end-of-buffer
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if (ch == '"')
                            {
                                end++; break;
                            }
                            else if (ch == '\\')
                            {
                                // escape sequence
                                end++;
                                if (end == N)
                                {
                                    break;
                                }
                                ch = txt[end];
                                if (ch == 'u')
                                {
                                    end += 4;
                                    if (N <= end)
                                    {
                                        end = N; break;
                                    }
                                }
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.Comment)
                    {
                        if (end == N)
                        {
                            continue; // this was not the start of a comment; it was just a single "/" and we don't care to color it
                        }
                        char ch = txt[end];
                        if (ch == '/')
                        {
                            // a short comment, to the end of the line.
                            end = newSnapshot.GetLineFromPosition(start + end).End.Position - start;
                        }
                        else if (ch == '*')
                        {
                            // a long comment; find the matching "*/"
                            end++;
                            commentStart = new SnapshotPoint(newSnapshot, start + cur);
                            Contract.Assert(longCommentDepth == 0);
                            longCommentDepth = 1;
                            ScanForEndOfComment(txt, ref longCommentDepth, ref end);
                            if (longCommentDepth == 0)
                            {
                                // we finished scanning a long comment, and "end" is set to right after it
                                newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, start + end), DafnyTokenKind.Comment));
                            }
                            else
                            {
                                commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, start + end);
                            }
                            continue;
                        }
                        else
                        {
                            // not a comment; it was just a single "/" and we don't care to color it
                            continue;
                        }
                    }
                    else
                    {
                        int trailingDigits = 0;
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('a' <= ch && ch <= 'z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('A' <= ch && ch <= 'Z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('0' <= ch && ch <= '9')
                            {
                                trailingDigits++;
                            }
                            else if (ch == '\'' || ch == '_' || ch == '?' || ch == '\\')
                            {
                                trailingDigits = 0;
                            }
                            else
                            {
                                break;
                            }
                        }
                        // we have a keyword or an identifier
                        string s = txt.Substring(cur, end - cur);
                        if (0 < trailingDigits && s.Length == 5 + trailingDigits && s.StartsWith("array") && s[5] != '0' && (trailingDigits != 1 || s[5] != '1'))
                        {
                            // this is a keyword for a built-in type (array2, array3, ...)
                            ty = DafnyTokenKind.BuiltInType;
                        }
                        else if (0 < trailingDigits && s.Length == 2 + trailingDigits && s.StartsWith("bv") && (s[2] != '0' || trailingDigits == 1))
                        {
                            // this is a keyword for a built-in type (bv0, bv1, ...)
                            ty = DafnyTokenKind.BuiltInType;
                        }
                        else
                        {
                            switch (s)
                            {
                                #region keywords
                            case "abstract":
                            case "allocated":
                            case "as":
                            case "assert":
                            case "assume":
                            case "break":
                            case "by":
                            case "calc":
                            case "case":
                            case "class":
                            case "const":
                            case "trait":
                            case "extends":
                            case "codatatype":
                            case "colemma":
                            case "constructor":
                            case "copredicate":
                            case "datatype":
                            case "else":
                            case "exists":
                            case "export":
                            case "false":
                            case "forall":
                            case "fresh":
                            case "function":
                            case "ghost":
                            case "if":
                            case "import":
                            case "in":
                            case "include":
                            case "inductive":
                            case "iterator":
                            case "label":
                            case "lemma":
                            case "match":
                            case "method":
                            case "modify":
                            case "module":
                            case "new":
                            case "newtype":
                            case "null":
                            case "old":
                            case "opened":
                            case "predicate":
                            case "print":
                            case "protected":
                            case "refines":
                            case "return":
                            case "returns":
                            case "static":
                            case "then":
                            case "this":
                            case "true":
                            case "twostate":
                            case "type":
                            case "unchanged":
                            case "var":
                            case "where":
                            case "while":
                            case "yield":
                            case "yields":
                                #endregion
                                break;

                                #region keywords in specification clauses
                            case "decreases":
                            case "ensures":
                            case "invariant":
                            case "modifies":
                            case "provides":
                            case "reads":
                            case "requires":
                            case "reveals":
                            case "witness":
                                // "yields" plays a dual role
                                #endregion
                                ty = DafnyTokenKind.SpecificationClause;
                                break;

                                #region keywords for built-in types
                            case "array":
                            case "bool":
                            case "char":
                            case "imap":
                            case "int":
                            case "iset":
                            case "map":
                            case "multiset":
                            case "nat":
                            case "object":
                            case "ORDINAL":
                            case "real":
                            case "seq":
                            case "set":
                            case "string":
                                #endregion
                                ty = DafnyTokenKind.BuiltInType;
                                break;

                            default:
                                continue; // it was an identifier, so we don't color it
                            }
                        }
                    }
                    newRegions.Add(new TokenRegion(new SnapshotPoint(newSnapshot, start + cur), new SnapshotPoint(newSnapshot, start + end), ty));
                }
OUTER_CONTINUE:
                done = true;
                if (longCommentDepth != 0)
                {
                    // we need to look into the next line
                    ITextSnapshotLine currLine = newSnapshot.GetLineFromPosition(start + N);
                    if ((currLine.LineNumber + 1) < newSnapshot.LineCount)
                    {
                        ITextSnapshotLine nextLine = newSnapshot.GetLineFromLineNumber(currLine.LineNumber + 1);
                        txt   = nextLine.GetText();
                        start = nextLine.Start;
                        // we are done scanning the current buffer, but not the whole file yet.
                        // we need to continue to find the enclosing "*/", or until the end of the file.
                        done = false;
                    }
                    else
                    {
                        // This was a malformed comment, running to the end of the buffer.  Above, we let "commentEndAsWeKnowIt" be the end of the
                        // last line, so we can use it here.
                        newRegions.Add(new TokenRegion(commentStart, commentEndAsWeKnowIt, DafnyTokenKind.Comment));
                    }
                }
            }
            return(new SnapshotPoint(newSnapshot, start + N));
        }
Example #4
0
 public DafnyTokenTag(DafnyTokenKind kind)
 {
     this.Kind = kind;
 }
Example #5
0
        private static List <TokenRegion> Rescan(ITextSnapshot newSnapshot)
        {
            List <TokenRegion> newRegions = new List <TokenRegion>();

            int           longCommentDepth     = 0;
            SnapshotPoint commentStart         = new SnapshotPoint(); // used only when longCommentDepth != 0
            SnapshotPoint commentEndAsWeKnowIt = new SnapshotPoint(); // used only when longCommentDepth != 0

            foreach (ITextSnapshotLine line in newSnapshot.Lines)
            {
                string txt = line.GetText(); // the current line (without linebreak characters)
                int    N   = txt.Length;     // length of the current line
                int    cur = 0;              // offset into the current line

                if (longCommentDepth != 0)
                {
                    ScanForEndOfComment(txt, ref longCommentDepth, ref cur);
                    if (longCommentDepth == 0)
                    {
                        // we just finished parsing a long comment
                        newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, line.Start + cur), DafnyTokenKind.Comment));
                    }
                    else
                    {
                        // we're still parsing the long comment
                        Contract.Assert(cur == txt.Length);
                        commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, line.Start + cur);
                        goto OUTER_CONTINUE;
                    }
                }

                // repeatedly get the remaining tokens from this line
                int end; // offset into the current line
                for (; ; cur = end)
                {
                    // advance to the first character of a keyword or token
                    DafnyTokenKind ty = DafnyTokenKind.Keyword;
                    for (; ; cur++)
                    {
                        if (N <= cur)
                        {
                            // we've looked at everything in this line
                            goto OUTER_CONTINUE;
                        }
                        char ch = txt[cur];
                        if ('a' <= ch && ch <= 'z')
                        {
                            break;
                        }
                        if ('A' <= ch && ch <= 'Z')
                        {
                            break;
                        }
                        if ('0' <= ch && ch <= '9')
                        {
                            ty = DafnyTokenKind.Number; break;
                        }
                        if (ch == '\'' || ch == '_' || ch == '?' || ch == '\\')
                        {
                            break;                                          // parts of identifiers
                        }
                        if (ch == '"')
                        {
                            ty = DafnyTokenKind.String; break;
                        }
                        if (ch == '/')
                        {
                            ty = DafnyTokenKind.Comment; break;
                        }
                    }

                    // advance to the end of the token
                    end = cur + 1; // offset into the current line
                    if (ty == DafnyTokenKind.Number)
                    {
                        // scan the rest of this number
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('0' <= ch && ch <= '9')
                            {
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.String)
                    {
                        // scan the rest of this string, but not past the end-of-line
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if (ch == '"')
                            {
                                end++; break;
                            }
                            else if (ch == '\\')
                            {
                                // escape sequence
                                end++;
                                if (end == N)
                                {
                                    break;
                                }
                                ch = txt[end];
                                if (ch == 'u')
                                {
                                    end += 4;
                                    if (N <= end)
                                    {
                                        end = N; break;
                                    }
                                }
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.Comment)
                    {
                        if (end == N)
                        {
                            continue; // this was not the start of a comment; it was just a single "/" and we don't care to color it
                        }
                        char ch = txt[end];
                        if (ch == '/')
                        {
                            // a short comment
                            end = N;
                        }
                        else if (ch == '*')
                        {
                            // a long comment; find the matching "*/"
                            end++;
                            commentStart = new SnapshotPoint(newSnapshot, line.Start + cur);
                            Contract.Assert(longCommentDepth == 0);
                            longCommentDepth = 1;
                            ScanForEndOfComment(txt, ref longCommentDepth, ref end);
                            if (longCommentDepth == 0)
                            {
                                // we finished scanning a long comment, and "end" is set to right after it
                                newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, line.Start + end), DafnyTokenKind.Comment));
                            }
                            else
                            {
                                commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, line.Start + end);
                            }
                            continue;
                        }
                        else
                        {
                            // not a comment; it was just a single "/" and we don't care to color it
                            continue;
                        }
                    }
                    else
                    {
                        int trailingDigits = 0;
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('a' <= ch && ch <= 'z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('A' <= ch && ch <= 'Z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('0' <= ch && ch <= '9')
                            {
                                trailingDigits++;
                            }
                            else if (ch == '\'' || ch == '_' || ch == '?' || ch == '\\')
                            {
                                trailingDigits = 0;
                            }
                            else
                            {
                                break;
                            }
                        }
                        // we have a keyword or an identifier
                        string s = txt.Substring(cur, end - cur);
                        if (0 < trailingDigits && s.Length == 5 + trailingDigits && s.StartsWith("array") && s[5] != '0' && (trailingDigits != 1 || s[5] != '1'))
                        {
                            // this is a keyword (array2, array3, ...)
                        }
                        else
                        {
                            switch (s)
                            {
                                #region keywords
                            case "abstract":
                            case "array":
                            case "as":
                            case "assert":
                            case "assume":
                            case "bool":
                            case "break":
                            case "calc":
                            case "case":
                            case "char":
                            case "class":
                            case "trait":
                            case "extends":
                            case "codatatype":
                            case "colemma":
                            case "constructor":
                            case "copredicate":
                            case "datatype":
                            case "decreases":
                            case "default":
                            case "else":
                            case "ensures":
                            case "exists":
                            case "false":
                            case "forall":
                            case "free":
                            case "fresh":
                            case "function":
                            case "ghost":
                            case "if":
                            case "imap":
                            case "import":
                            case "in":
                            case "include":
                            case "inductive":
                            case "int":
                            case "invariant":
                            case "iterator":
                            case "label":
                            case "lemma":
                            case "map":
                            case "match":
                            case "method":
                            case "modifies":
                            case "modify":
                            case "module":
                            case "multiset":
                            case "nat":
                            case "new":
                            case "newtype":
                            case "null":
                            case "object":
                            case "old":
                            case "opened":
                            case "predicate":
                            case "print":
                            case "protected":
                            case "reads":
                            case "real":
                            case "refines":
                            case "requires":
                            case "return":
                            case "returns":
                            case "seq":
                            case "set":
                            case "static":
                            case "string":
                            case "then":
                            case "this":
                            case "true":
                            case "type":
                            case "var":
                            case "where":
                            case "while":
                            case "yield":
                            case "yields":
                                #endregion
                                break;

                            default:
                                continue; // it was an identifier, so we don't color it
                            }
                        }
                    }

                    newRegions.Add(new TokenRegion(new SnapshotPoint(newSnapshot, line.Start + cur), new SnapshotPoint(newSnapshot, line.Start + end), ty));
                }
                OUTER_CONTINUE :;
            }

            if (longCommentDepth != 0)
            {
                // This was a malformed comment, running to the end of the buffer.  Above, we let "commentEndAsWeKnowIt" be the end of the
                // last line, so we can use it here.
                newRegions.Add(new TokenRegion(commentStart, commentEndAsWeKnowIt, DafnyTokenKind.Comment));
            }

            return(newRegions);
        }