/// <summary> /// Initializes a new instance of the <see cref="UvssLexerToken"/> structure. /// </summary> /// <param name="type">A <see cref="UvssLexerTokenType"/> value that indicates the token's type.</param> /// <param name="sourceOffset">The token's offset within the source text.</param> /// <param name="sourceLength">The token's length within the source text.</param> /// <param name="sourceLine">The index of the line on which the token appears in the source text.</param> /// <param name="sourceColumn">The index of the column in which the token appears in the source text.</param> /// <param name="text">The token text.</param> public UvssLexerToken(UvssLexerTokenType type, Int32 sourceOffset, Int32 sourceLength, Int32 sourceLine, Int32 sourceColumn, String text) { this.Type = type; this.SourceOffset = sourceOffset; this.SourceLength = sourceLength; this.SourceLine = sourceLine; this.SourceColumn = sourceColumn; this.Text = text; }
/// <summary> /// Reads an extended token, such as a comment, which continues until reaching some termination condition. /// </summary> /// <param name="source">The source string.</param> /// <param name="position">The position at which the token begins.</param> /// <param name="tokenType">The token's type.</param> /// <param name="tokenText">The token's text.</param> private static void ReadExtendedToken(String source, Int32 position, ref UvssLexerTokenType tokenType, ref String tokenText) { switch (tokenType) { case UvssLexerTokenType.SingleLineComment: ReadSingleLineComment(source, position, ref tokenType, ref tokenText); break; case UvssLexerTokenType.MultiLineComment: ReadMultiLineComment(source, position, ref tokenType, ref tokenText); break; } }
/// <summary> /// Initializes a new instance of the <see cref="UvssLexerToken"/> structure. /// </summary> /// <param name="tokenType">The token's type.</param> /// <param name="start">The index of the token within the source text.</param> /// <param name="length">The length of the token within the source text.</param> /// <param name="line">The line of source code that contains the token.</param> /// <param name="value">The token's associated value.</param> public UvssLexerToken(UvssLexerTokenType tokenType, Int32 start, Int32 length, Int32 line, String value = null) { this.tokenType = tokenType; this.start = start; this.length = length; this.line = line; switch (tokenType) { case UvssLexerTokenType.WhiteSpace: this.value = " "; break; case UvssLexerTokenType.OpenParenthesis: this.value = "("; break; case UvssLexerTokenType.CloseParenthesis: this.value = ")"; break; case UvssLexerTokenType.OpenCurlyBrace: this.value = "{"; break; case UvssLexerTokenType.CloseCurlyBrace: this.value = "}"; break; case UvssLexerTokenType.Colon: this.value = ":"; break; case UvssLexerTokenType.Semicolon: this.value = ";"; break; case UvssLexerTokenType.Comma: this.value = ","; break; case UvssLexerTokenType.UniversalSelector: this.value = "*"; break; default: this.value = value; break; } }
/// <summary> /// Reads a multi-line comment token starting at the specified position in the source. /// </summary> /// <param name="source">The source string.</param> /// <param name="position">The source position at which the comment token begins.</param> /// <param name="tokenType">The token's type.</param> /// <param name="tokenText">The full text of the multi-line comment token.</param> private static void ReadMultiLineComment(String source, Int32 position, ref UvssLexerTokenType tokenType, ref String tokenText) { var offset = position; var length = source.Length - position; for (int i = position + tokenText.Length; i < source.Length - 1; i++) { if (source[i] == '*' && source[i + 1] == '/') { length = (i - offset) + 2; break; } } tokenText = source.Substring(offset, length); }
/// <summary> /// Given a <see cref="Match"/> instance, determines the type and text of the corresponding lexer token. /// </summary> /// <param name="match">The <see cref="Match"/> instance to evaluate.</param> /// <param name="tokenType">The lexed token's type.</param> /// <param name="tokenText">The lexed token's text.</param> /// <returns>true if the <see cref="Match"/> represented a valid token; otherwise, false.</returns> private static Boolean GetTokenInfoFromRegexMatch(Match match, out UvssLexerTokenType tokenType, out String tokenText) { for (int i = 1; i < match.Groups.Count; i++) { var group = match.Groups[i]; if (group.Success) { tokenType = GetTokenTypeFromName(regexGroupNames[i]); tokenText = group.Value; return(true); } } tokenType = UvssLexerTokenType.Unknown; tokenText = null; return(false); }
/// <summary> /// Reads a single-line comment token starting at the specified position in the source. /// </summary> /// <param name="source">The source string.</param> /// <param name="position">The source position at which the comment token begins.</param> /// <param name="tokenType">The token's type.</param> /// <param name="tokenText">The full text of the single-line comment token.</param> private static void ReadSingleLineComment(String source, Int32 position, ref UvssLexerTokenType tokenType, ref String tokenText) { var offset = position; var length = tokenText.Length; for (int i = position + tokenText.Length; i < source.Length; i++) { if (source.Length == i + 1) { length = source.Length - offset; break; } if ((source[i] == '\r' && source[i + 1] == '\n') || source[i] == '\n') { length = i - offset; break; } } tokenText = source.Substring(offset, length); }
/// <summary> /// Throws an exception if the specified token does not match the specified parameters. /// </summary> /// <param name="state">The parser state.</param> /// <param name="token">The token to evaluate.</param> /// <param name="type">The desired token type.</param> /// <param name="value">The desired token value.</param> private static void MatchTokenOrFail(UvssParserState state, UvssLexerToken? token, UvssLexerTokenType type, String value = null) { if (token == null) ThrowUnexpectedEOF(state); if (token.Value.TokenType != type) ThrowExpectedToken(state, token.Value, type); if (value != null && !String.Equals(token.Value.Value, value, StringComparison.OrdinalIgnoreCase)) ThrowExpectedValue(state, token.Value, value); }
/// <summary> /// Gets a value indicating whether the specified token is a match for the specified parameters. /// </summary> /// <param name="token">The token to evaluate.</param> /// <param name="type">The desired token type.</param> /// <param name="value">The desired token value.</param> /// <returns><c>true</c> if the specified token is a match; otherwise, <c>false</c>.</returns> private static Boolean MatchToken(UvssLexerToken? token, UvssLexerTokenType type, String value = null) { if (token == null) return false; if (token.Value.TokenType != type) return false; if (value != null && !String.Equals(token.Value.Value, value, StringComparison.OrdinalIgnoreCase)) return false; return true; }
/// <summary> /// Attempts to consume a punctuation token. /// </summary> private static Boolean ConsumePunctuation(UvssLexerTokenType type, Char punctuation, String input, IList<UvssLexerToken> output, Int32 line, ref Int32 ix) { if (IsPastEndOfStream(input, ix)) return false; if (input[ix] == punctuation) { var token = new UvssLexerToken(type, ix, 1, line); output.Add(token); ix++; return true; } return false; }
/// <summary> /// Determines whether the last token in the output sequence has the specified type. /// </summary> private static Boolean LastTokenHasType(IList<UvssLexerToken> output, UvssLexerTokenType type) { if (output.Count == 0) return false; var token = output[output.Count - 1]; return token.TokenType == type; }
/// <summary> /// Retrieves all of the tokens between a matching pair of tokens. /// </summary> /// <param name="state">The parser state.</param> /// <param name="start">The type of the first token in the matching pair.</param> /// <param name="end">The type of the second token in the matching pair.</param> /// <returns>A collection containing the tokens between the specified matching pair of tokens.</returns> private static IList<UvssLexerToken> GetTokensBetweenMatchingPair(UvssParserState state, UvssLexerTokenType start, UvssLexerTokenType end) { if (state.CurrentToken.TokenType != start) ThrowExpectedToken(state, state.CurrentToken, start); var level = 1; var tokens = new List<UvssLexerToken>(); state.Advance(); while (true) { if (state.IsPastEndOfStream) ThrowUnterminatedSequence(state); var token = state.Consume(); if (token.TokenType == start) { level++; } else if (token.TokenType == end) { level--; } if (level == 0) { break; } tokens.Add(token); } return tokens; }
/// <summary> /// Given a <see cref="Match"/> instance, determines the type and text of the corresponding lexer token. /// </summary> /// <param name="match">The <see cref="Match"/> instance to evaluate.</param> /// <param name="tokenType">The lexed token's type.</param> /// <param name="tokenText">The lexed token's text.</param> /// <returns>true if the <see cref="Match"/> represented a valid token; otherwise, false.</returns> private static Boolean GetTokenInfoFromRegexMatch(Match match, out UvssLexerTokenType tokenType, out String tokenText) { for (int i = 1; i < match.Groups.Count; i++) { var group = match.Groups[i]; if (group.Success) { tokenType = GetTokenTypeFromName(regexGroupNames[i]); tokenText = group.Value; return true; } } tokenType = UvssLexerTokenType.Unknown; tokenText = null; return false; }
/// <summary> /// Throws an exception indicating that an expected token was not found. /// </summary> /// <param name="state">The parser state.</param> /// <param name="token">The invalid token.</param> /// <param name="expected">The expected token type.</param> private static void ThrowExpectedToken(UvssParserState state, UvssLexerToken token, UvssLexerTokenType expected) { var lineNumber = token.Line; throw new UvssException(PresentationStrings.StyleSheetSyntaxExpectedToken.Format(lineNumber, token.TokenType, expected)); }