예제 #1
0
 private CssToken ScanSubstringMatch()
 {
     CssToken token = null;
     if (PeekChar() == '=')
     {
         // skip the two characters and return a substring match
         NextChar();
         NextChar();
         token = new CssToken(TokenType.SubstringMatch, c_substringMatch, m_context);
     }
     else
     {
         // see if this asterisk is a namespace portion of an identifier
         token = ScanIdent();
     }
     if (token == null)
     {
         // skip the * and return a character token
         NextChar();
         token = new CssToken(TokenType.Character, '*', m_context);
     }
     return token;
 }
예제 #2
0
 private CssToken ScanSuffixMatch()
 {
     CssToken token = null;
     NextChar();
     if (m_currentChar == '=')
     {
         NextChar();
         token = new CssToken(TokenType.SuffixMatch, c_suffixMatch, m_context);
     }
     return (token != null ? token : new CssToken(TokenType.Character, '$', m_context));
 }
예제 #3
0
        private CssToken ScanNum()
        {
            CssToken token = null;
            string num = GetNum();
            if (num != null)
            {
                if (m_currentChar == '%')
                {
                    NextChar();

                    // let's always keep the percentage on the number, even if it's
                    // zero -- some things require it (like the rgb function)
                    token = new CssToken(
                      TokenType.Percentage,
                      num + '%',
                      m_context
                      );

                    // and make sure the "raw number" we keep has it as well
                    m_rawNumber += '%';
                }
                else
                {
                    string dimen = GetIdent();
                    if (dimen == null)
                    {
                        // if there is no identifier, it's a num.
                        token = new CssToken(TokenType.Number, num, m_context);
                    }
                    else
                    {
                        // add the dimension to the raw number
                        m_rawNumber += dimen;

                        // classify the dimension type
                        TokenType tokenType = TokenType.Dimension;
                        switch (dimen.ToUpperInvariant())
                        {
                            case "EM":          // font-size of the element
                            case "EX":          // x-height of the element's font
                            case "CH":          // width of the zero glyph in the element's font
                            case "REM":         // font-size of the root element
                            case "VW":          // viewport's width
                            case "VH":          // viewport's height
                            case "VM":          // viewport width or height, whichever is smaller of the two (use VMIN)
                            case "VMIN":        // minimum of the viewport's height and width
                            case "VMAX":        // maximum of the viewport's height and width
                            case "FR":          // fraction of available space
                            case "GR":          // grid unit
                            case "GD":          // text grid unit
                                tokenType = TokenType.RelativeLength;
                                break;

                            case "CM":          // centimeters
                            case "MM":          // millimeters
                            case "IN":          // inches (1in == 2.54cm)
                            case "PX":          // pixels (1px == 1/96in)
                            case "PT":          // points (1pt == 1/72in)
                            case "PC":          // picas (1pc == 12pt)
                                tokenType = TokenType.AbsoluteLength;
                                break;

                            case "DEG":         // degrees (360deg == 1 full circle)
                            case "GRAD":        // gradians (400grad == 1 full circle)
                            case "RAD":         // radians (2*pi radians == 1 full circle)
                            case "TURN":        // turns (1turn == 1 full circle)
                                tokenType = TokenType.Angle;
                                break;

                            case "MS":          // milliseconds
                            case "S":           // seconds
                                tokenType = TokenType.Time;
                                break;

                            case "DPI":         // dots per inch
                            case "DPCM":        // dots per centimeter
                            case "DPPX":        // dots per pixel
                                tokenType = TokenType.Resolution;
                                break;

                            case "HZ":          // hertz
                            case "KHZ":         // kilohertz
                                tokenType = TokenType.Frequency;
                                break;

                            case "DB":          // decibel
                            case "ST":          // semitones
                                tokenType = TokenType.Speech;
                                break;
                        }

                        // if the number is zero, it really doesn't matter what the dimensions are so we can remove it
                        // EXCEPT for Angles, Times, Frequencies, and Resolutions - they should not get their units
                        // stripped, since we can only do that for LENGTHS as per the specs.
                        // And percentages, since 0% is the same as 0. (true?)
                        // ALSO, if we don't recognize the dimension, leave it -- it could be a browser hack or some
                        // other intentional construct.
                        if (num == "0"
                            && tokenType != TokenType.Dimension
                            && tokenType != TokenType.Angle
                            && tokenType != TokenType.Time
                            && tokenType != TokenType.Frequency
                            && tokenType != TokenType.Resolution)
                        {
                            token = new CssToken(TokenType.Number, num, m_context);
                        }
                        else
                        {
                            token = new CssToken(tokenType, num + dimen, m_context);
                        }
                    }
                }
            }
            else if (m_currentChar == '.')
            {
                token = new CssToken(TokenType.Character, '.', m_context);
                NextChar();
            }
            else
            {
                // this function is only called when the first character is
                // a digit or a period. So this block should never execute, since
                // a digit will produce a num, and if it doesn't, the previous block
                // picks up the period.
                ReportError(1, CssErrorCode.UnexpectedNumberCharacter, m_currentChar);
            }

            return token;
        }
예제 #4
0
        private CssToken ScanProgId()
        {
            CssToken token = null;
            StringBuilder sb = new StringBuilder();
            sb.Append("progid:");
            string ident = GetIdent();
            while (ident != null)
            {
                sb.Append(ident);
                if (m_currentChar == '.')
                {
                    sb.Append('.');
                    NextChar();
                }
                ident = GetIdent();
            }
            if (m_currentChar == '(')
            {
                sb.Append('(');
                NextChar();

                token = new CssToken(TokenType.ProgId, sb.ToString(), m_context);
            }
            else
            {
                ReportError(1, CssErrorCode.ExpectedOpenParenthesis);
            }
            return token;
        }
예제 #5
0
        private CssToken ScanImportant()
        {
            CssToken token = null;
            NextChar();

            string w = GetW();
            if (char.ToUpperInvariant(m_currentChar) == 'I')
            {
                if (ReadString("IMPORTANT"))
                {
                    // no matter what the case or whether or not there is space between the ! and
                    // the important, we're going to represent this token as having no space and all
                    // lower-case.
                    token = new CssToken(TokenType.ImportantSymbol, "!important", m_context);
                }
            }
            // if the token is still null but we had found some whitespace,
            // we need to push a whitespace char back onto the read-ahead
            if (token == null && w.Length > 0)
            {
                PushChar(' ');
            }

            return (token != null ? token : new CssToken(TokenType.Character, '!', m_context));
        }
예제 #6
0
 private CssToken ScanIncludes()
 {
     CssToken token = null;
     NextChar();
     if (m_currentChar == '=')
     {
         NextChar();
         token = new CssToken(TokenType.Includes, c_scanIncludes, m_context);
     }
     return (token != null ? token : new CssToken(TokenType.Character, '~', m_context));
 }
예제 #7
0
        private CssToken ScanDashMatch()
        {
            CssToken token = null;
            // if the next character is an equals sign, then we have a dash-match
            if (PeekChar() == '=')
            {
                // skip the two characters
                NextChar();
                NextChar();
                token = new CssToken(TokenType.DashMatch, c_dashMatch, m_context);
            }
            else
            {
                // see if this is the start of a namespace ident
                token = ScanIdent();
            }

            // if we haven't computed a token yet, it's just a character
            if (token == null)
            {
                NextChar();
                token = new CssToken(TokenType.Character, '|', m_context);
            }
            return token;
        }
예제 #8
0
        private string NextSignificantToken()
        {
            // MOST of the time we won't need to save anything,
            // so don't bother allocating a string builder unless we need it
            StringBuilder sb = null;

            // get the next token
            m_currentToken = m_scanner.NextToken();
            m_encounteredNewLine = m_scanner.GotEndOfLine;
            while (CurrentTokenType == TokenType.Space || CurrentTokenType == TokenType.Comment)
            {
                // if this token is a comment, add it to the builder
                if (CurrentTokenType == TokenType.Comment)
                {
                    // check for important comment
                    string commentText = CurrentTokenText;
                    bool importantComment = commentText.StartsWith("/*!", StringComparison.Ordinal);
                    if (importantComment)
                    {
                        // get rid of the exclamation mark in some situations
                        commentText = NormalizeImportantComment(commentText);
                    }

                    // if the comment mode is none, don't ever output it.
                    // if the comment mode is all, always output it.
                    // otherwise only output it if it is an important comment.
                    bool writeComment = Settings.CommentMode == CssComment.All
                        || (importantComment && Settings.CommentMode != CssComment.None);

                    if (!importantComment)
                    {
                        // see if this is a value-replacement id
                        Match match = s_valueReplacement.Match(commentText);
                        if (match.Success)
                        {
                            // check all the resource strings objects to see if one is a match.
                            m_valueReplacement = null;

                            var resourceList = Settings.ResourceStrings;
                            if (resourceList.Count > 0)
                            {
                                // get the id of the string we want to substitute
                                string ident = match.Result("${id}");

                                // walk the list BACKWARDS so later resource string objects override previous ones
                                for (var ndx = resourceList.Count - 1; ndx >= 0; --ndx)
                                {
                                    m_valueReplacement = resourceList[ndx][ident];
                                    if (m_valueReplacement != null)
                                    {
                                        break;
                                    }
                                }
                            }

                            // if there is such a string, we will have saved the value in the value replacement
                            // variable so it will be substituted for the next value.
                            // if there is no such string, we ALWAYS want to output the comment so we know
                            // there was a problem (even if the comments mode is to output none)
                            writeComment = m_valueReplacement == null;
                            if (writeComment)
                            {
                                // make sure the comment is normalized
                                commentText = NormalizedValueReplacementComment(commentText);
                            }
                        }
                    }

                    if (writeComment)
                    {
                        // if we haven't yet allocated a string builder, do it now
                        if (sb == null)
                        {
                            sb = new StringBuilder();
                        }

                        // add the comment to the builder
                        sb.Append(commentText);
                    }
                }

                // next token
                m_currentToken = m_scanner.NextToken();
                m_encounteredNewLine = m_encounteredNewLine || m_scanner.GotEndOfLine;
            }

            // return any comments we found in the mean time
            return (sb == null ? string.Empty : sb.ToString());
        }
예제 #9
0
 private CssToken ScanCDO()
 {
     CssToken token = null;
     NextChar(); // points to !?
     if (m_currentChar == '!')
     {
         if (PeekChar() == '-')
         {
             NextChar(); // points to -
             if (PeekChar() == '-')
             {
                 NextChar(); // points to second hyphen
                 NextChar();
                 token = new CssToken(TokenType.CommentOpen, c_commentStart, m_context);
             }
             else
             {
                 // we want to just return the < character, but
                 // we're currently pointing to the first hyphen,
                 // so we need to add the ! to the read ahead buffer
                 PushChar('!');
             }
         }
     }
     return (token != null ? token : token = new CssToken(TokenType.Character, '<', m_context));
 }
예제 #10
0
        private CssToken ScanComment()
        {
            CssToken token = null;
            NextChar();
            if (m_currentChar == '*')
            {
                NextChar();
                // everything is a comment until we get to */
                StringBuilder sb = new StringBuilder();
                sb.Append("/*");

                bool terminated = false;
                while (m_currentChar != '\0')
                {
                    sb.Append(m_currentChar);
                    if (m_currentChar == '*' && PeekChar() == '/')
                    {
                        sb.Append('/');
                        NextChar(); // now points to /
                        NextChar(); // now points to following character

                        // check for comment-hack 2 -- NS4 sees /*/*//*/ as a single comment
                        // while everyone else properly parses that as two comments, which hides everything
                        // after this construct until the next comment. So this hack shows the stuff
                        // between ONLY to NS4. But we still want to crunch it, so if we just found
                        // a comment like /*/*/, check to see if the next characters are /*/. If so,
                        // treat it like the single comment NS4 sees.
                        // (and don't forget that if we want to keep them, we've turned them both into important comments)
                        if (sb.ToString() == "/*!/*/" && ReadString("/*/"))
                        {
                            // read string will leave the current character after the /*/ string,
                            // so add the part we just read to the string builder and we'll break
                            // out of the loop
                            sb.Append("/*/");
                        }
                        terminated = true;
                        break;
                    }
                    NextChar();
                }

                if (!terminated)
                {
                    ReportError(0, CssErrorCode.UnterminatedComment);
                }

                var comment = sb.ToString();
                if (string.Compare(comment, 2, "/#SOURCE", 0, 8, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    // found our special comment: /*/#SOURCE line col path */
                    var match = s_sourceDirective.Match(comment);
                    if (match != null)
                    {
                        int line, column;
                        if (int.TryParse(match.Result("${line}"), out line)
                            && int.TryParse(match.Result("${col}"), out column))
                        {
                            // we got a proper line, column, and non-blank path. reset our context
                            // with the new line and column.
                            this.OnContextChange(
                                match.Result("${path}"),
                                line,
                                column);

                            // now, this is weird. by AjaxMin convention, there should be NOTHING after this comment
                            // but whitespace and a single line-terminator. So we will skip EVERYTHING after this comment up
                            // to the first line-terminator, and then eat that first line-terminator. So it's possible to
                            // completely ignore code by putting it between this multiline comment and the end of its line.
                            SkipToNextLineWithoutUpdate();

                            // return null so this token gets skipped
                            return null;
                        }
                    }
                }

                token = new CssToken(TokenType.Comment, comment, m_context);
            }
            else if (m_currentChar == '/')
            {
                // we found '//' -- it's a JS-style single-line comment which isn't strictly
                // supported by CSS, but we're going to treat as a valid comment because
                // developers like using them. We're not going to persist them, though -- we're
                // going to eat these comments, since they're not valid CSS.

                // first check for our special ///#source directive.
                // We're on the second slash; see if the NEXT character is a third slash
                if (PeekChar() == '/')
                {
                    // found '///'
                    NextChar();

                    // now w're on the third slash; see if the NEXT character is a pound-sign
                    if (PeekChar() == '#')
                    {
                        // okay, we have ///#, which we are going to reserve for all AjaxMin directive comments.
                        // so the source better not have something meaningful for the rest of the line.
                        NextChar();

                        // now we're on the pound-sign. See if we have the source directive
                        if (ReadString("#SOURCE"))
                        {
                            // we have a source directive: ///#source line col file
                            // skip space
                            DirectiveSkipSpace();

                            // pull the line and column numbers. Must be positive integers greater than zero.
                            int line = DirectiveScanInteger();
                            if (line > 0)
                            {
                                DirectiveSkipSpace();
                                int column = DirectiveScanInteger();
                                if (column > 0)
                                {
                                    DirectiveSkipSpace();

                                    // the rest of the comment line is the file path.
                                    var sb = new StringBuilder();
                                    while (m_currentChar != '\n' && m_currentChar != '\r')
                                    {
                                        sb.Append(m_currentChar);
                                        DirectiveNextChar();
                                    }

                                    var fileContext = sb.ToString().TrimEnd();
                                    if (!string.IsNullOrEmpty(fileContext))
                                    {
                                        // we got a proper line, column, and non-blank path. reset our context
                                        // with the new line and column.
                                        this.OnContextChange(fileContext, line, column);

                                        // START SPECIAL PROCESSING
                                        SkipToNextLineWithoutUpdate();

                                        // return null here so we don't fall through and return a / character.
                                        return null;
                                    }
                                }
                            }
                        }
                    }
                }

                // eat the comment up to, but not including, the next line terminator
                while (m_currentChar != '\n' && m_currentChar != '\r' && m_currentChar != '\0')
                {
                    NextChar();
                }

                // if we wanted to maintain these comments, we would set the token
                // variable to a new CssToken object of type comment. But we don't, so
                // just return null so that the scanner will go around again.
                return null;
            }

            if (token == null)
            {
                // not a comment
                token = new CssToken(TokenType.Character, '/', m_context);
            }

            return token;
        }
예제 #11
0
 private CssToken ScanCDC()
 {
     CssToken token = null;
     NextChar(); // points to second hyphen?
     if (m_currentChar == '-')
     {
         if (PeekChar() == '>')
         {
             NextChar(); // points to >
             NextChar();
             token = new CssToken(TokenType.CommentClose, c_commentEnd, m_context);
         }
     }
     return token;
 }
예제 #12
0
        public CssToken NextToken()
        {
            GotEndOfLine = false;

            // advance the context
            m_context.Advance();
            m_rawNumber = null;

            CssToken token = null;
            bool tryAgain;
            do
            {
                tryAgain = false;
                switch (m_currentChar)
                {
                    case '\0':
                        // end of file
                        m_isAtEOF = true;
                        break;

                    case '\r':
                    case '\n':
                    case '\f':
                        // we hit an end-of-line character, but treat it like any other whitespace
                        GotEndOfLine = true;
                        goto case ' ';

                    case ' ':
                    case '\t':
                        // no matter how much whitespace is actually in
                        // the stream, we're just going to encode a single
                        // space in the token itself
                        while (IsSpace(m_currentChar))
                        {
                            if (m_currentChar == '\r' || m_currentChar == '\n' || m_currentChar == '\f')
                            {
                                GotEndOfLine = true;
                            }

                            NextChar();
                        }
                        token = new CssToken(TokenType.Space, ' ', m_context);
                        break;

                    case '/':
                        token = ScanComment();
                        if (token == null)
                        {
                            // this could happen if we processed an ajaxmin directive.
                            // go around again and try for the next token
                            tryAgain = true;
                        }
                        break;

                    case '<':
                        if (AllowEmbeddedAspNetBlocks && PeekChar() == '%')
                        {
                            token = ScanAspNetBlock();
                        }
                        else
                        {
                            token = ScanCDO();
                        }
                        break;

                    case '-':
                        token = ScanCDC();
                        if (token == null)
                        {
                            // identifier in CSS2.1 and CSS3 can start with a hyphen
                            // to indicate vendor-specific identifiers.
                            string ident = GetIdent();
                            if (ident != null)
                            {
                                // vendor-specific identifier
                                // but first see if it's a vendor-specific function!
                                if (m_currentChar == '(')
                                {
                                    // it is -- consume the parenthesis; it's part of the token
                                    NextChar();
                                    token = new CssToken(TokenType.Function, "-" + ident + '(', m_context);
                                }
                                else
                                {
                                    // nope -- just a regular identifier
                                    token = new CssToken(TokenType.Identifier, "-" + ident, m_context);
                                }
                            }
                            else
                            {
                                // just a hyphen character
                                token = new CssToken(TokenType.Character, '-', m_context);
                            }
                        }
                        break;

                    case '~':
                        token = ScanIncludes();
                        break;

                    case '|':
                        token = ScanDashMatch();
                        break;

                    case '^':
                        token = ScanPrefixMatch();
                        break;

                    case '$':
                        token = ScanSuffixMatch();
                        break;

                    case '*':
                        token = ScanSubstringMatch();
                        break;

                    case '\'':
                    case '"':
                        token = ScanString();
                        break;

                    case '#':
                        token = ScanHash();
                        break;

                    case '@':
                        token = ScanAtKeyword();
                        break;

                    case '!':
                        token = ScanImportant();
                        break;

                    case 'U':
                    case 'u':
                        token = ScanUrl();
                        break;

                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '.':
                        token = ScanNum();
                        break;

                    default:
                        token = ScanIdent();
                        break;
                }
            } while (tryAgain);

            return token;
        }
예제 #13
0
 // skip to the next token, but output any comments we may find as we go along
 private TokenType NextToken()
 {
     m_currentToken = m_scanner.NextToken();
     m_encounteredNewLine = m_scanner.GotEndOfLine;
     while (CurrentTokenType == TokenType.Comment)
     {
         // the append statement might not actually append anything.
         // if it doesn't, we don't need to output a newline
         if (AppendCurrent())
         {
             NewLine();
         }
         m_currentToken = m_scanner.NextToken();
         m_encounteredNewLine = m_encounteredNewLine || m_scanner.GotEndOfLine;
     }
     return CurrentTokenType;
 }
예제 #14
0
        private CssToken ScanUnicodeRange()
        {
            // when called, the current character is the character *after* U+
            CssToken token = null;
            StringBuilder sb = new StringBuilder();
            sb.Append("U+");

            bool hasQuestions = false;
            int count = 0;
            bool leadingZero = true;
            int firstValue = 0;
            while (m_currentChar != '\0'
                && count < 6
                && (m_currentChar == '?' || (!hasQuestions && IsH(m_currentChar))))
            {
                // if this isn't a leading zero, reset the flag
                if (leadingZero && m_currentChar != '0')
                {
                    leadingZero = false;
                }

                if (m_currentChar == '?')
                {
                    hasQuestions = true;

                    // assume the digit is an "F" for maximum value
                    firstValue = firstValue*16 + HValue('F');
                }
                else
                {
                    firstValue = firstValue*16 + HValue(m_currentChar);
                }

                if (!leadingZero)
                {
                    sb.Append(m_currentChar);
                }

                ++count;
                NextChar();
            }

            if (count > 0)
            {
                // if the unicode value is out of range, throw an error
                if (firstValue < 0 || 0x10ffff < firstValue)
                {
                    // throw an error
                    ReportError(0, CssErrorCode.InvalidUnicodeRange, sb.ToString());
                }

                // if we still have the leading zero flag, then all the numbers were zero
                // and we didn't output any of them.
                if (leadingZero)
                {
                    // add one zero to keep it proper
                    sb.Append('0');
                }

                if (hasQuestions)
                {
                    // if there are question marks, then we're done
                    token = new CssToken(
                        TokenType.UnicodeRange,
                        sb.ToString(),
                        m_context);
                }
                else if (m_currentChar == '-')
                {
                    sb.Append('-');
                    NextChar();

                    count = 0;
                    leadingZero = true;
                    int secondValue = 0;
                    while (m_currentChar != '\0' && count < 6 && IsH(m_currentChar))
                    {
                        // if this isn't a leading zero, reset the flag
                        if (leadingZero && m_currentChar != '0')
                        {
                            leadingZero = false;
                        }

                        secondValue = secondValue * 16 + HValue(m_currentChar);

                        if (!leadingZero)
                        {
                            sb.Append(m_currentChar);
                        }

                        ++count;
                        NextChar();
                    }

                    if (count > 0)
                    {
                        // if we still have the leading zero flag, then all the numbers were zero
                        // and we didn't output any of them.
                        if (leadingZero)
                        {
                            // add one zero to keep it proper
                            sb.Append('0');
                        }

                        // check to make sure the second value is within range
                        // AND is greater than the first
                        if (secondValue < 0 || 0x10ffff < secondValue
                            || firstValue >= secondValue)
                        {
                            // throw an error
                            ReportError(0, CssErrorCode.InvalidUnicodeRange, sb.ToString());
                        }

                        token = new CssToken(
                            TokenType.UnicodeRange,
                            sb.ToString(),
                            m_context);
                    }
                }
                else
                {
                    // single code-point with at least one character
                    token = new CssToken(
                        TokenType.UnicodeRange,
                        sb.ToString(),
                        m_context);
                }
            }

            // if we don't hve a unicode range,
            // we need to return an ident token from the U we already scanned
            if (token == null)
            {
                // push everything back onto the buffer
                PushString(sb.ToString());
                token = ScanIdent();
            }

            return token;
        }
예제 #15
0
        private CssToken ScanIdent()
        {
            CssToken token = null;

            string ident = GetIdent();
            if (ident != null)
            {
                if (m_currentChar == '(')
                {
                    NextChar();
                    if (string.Compare(ident, "not", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        token = new CssToken(TokenType.Not, ident + '(', m_context);
                    }
                    else
                    {
                        token = new CssToken(TokenType.Function, ident + '(', m_context);
                    }
                }
                else if (string.Compare(ident, "progid", StringComparison.OrdinalIgnoreCase) == 0 && m_currentChar == ':')
                {
                    NextChar();
                    token = ScanProgId();
                }
                else
                {
                    token = new CssToken(TokenType.Identifier, ident, m_context);
                }
            }

            // if we failed somewhere in the processing...
            if (ident == null)
            {
                if (m_currentChar != '\0')
                {
                    // create a character token
                    token = new CssToken(TokenType.Character, m_currentChar, m_context);
                    NextChar();
                }
            }
            return token;
        }
예제 #16
0
        private CssToken ScanUrl()
        {
            CssToken token = null;
            if (PeekChar() == '+')
            {
                NextChar(); // now current is the +
                NextChar(); // now current is the first character after the +
                token = ScanUnicodeRange();
            }
            else if (ReadString("URL("))
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("url(");

                GetW();

                string url = GetString();
                if (url == null)
                {
                    url = GetUrl();
                }

                if (url != null)
                {
                    sb.Append(url);
                    GetW();
                    if (m_currentChar == ')')
                    {
                        sb.Append(')');
                        NextChar();

                        token = new CssToken(
                          TokenType.Uri,
                          sb.ToString(),
                          m_context
                          );
                    }
                }
            }
            return (token != null ? token : ScanIdent());
        }
예제 #17
0
 // just skip to the next token; don't skip over comments
 private TokenType NextRawToken()
 {
     m_currentToken = m_scanner.NextToken();
     m_encounteredNewLine = m_scanner.GotEndOfLine;
     return CurrentTokenType;
 }