Files
sdk/utils/css/tokenizer.dart
T
terry@google.com 64784aa1b1 Beginning of CSS parser using frog parsering infrastructure.
Change for in memory buffers.

BUG=
TEST=

Review URL: http://codereview.chromium.org//8498020

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@1752 260f80e4-7a28-3924-810f-c04153c831b5
2011-11-22 17:30:20 +00:00

124 lines
4.0 KiB
Dart

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class Tokenizer extends lang.TokenizerBase {
TokenKind cssTokens;
bool _selectorParsing;
Tokenizer(lang.SourceFile source, bool skipWhitespace, [int index = 0])
: super(source, skipWhitespace, index), _selectorParsing = false {
cssTokens = new TokenKind();
}
lang.Token next() {
// keep track of our starting position
_startIndex = _index;
if (_interpStack != null && _interpStack.depth == 0) {
var istack = _interpStack;
_interpStack = _interpStack.pop();
/* TODO(terry): Enable for variable and string interpolation.
* if (istack.isMultiline) {
* return finishMultilineStringBody(istack.quote);
* } else {
* return finishStringBody(istack.quote);
* }
*/
}
int ch;
ch = _nextChar();
switch(ch) {
case 0:
return _finishToken(TokenKind.END_OF_FILE);
case cssTokens.tokens[TokenKind.SPACE]:
case cssTokens.tokens[TokenKind.TAB]:
case cssTokens.tokens[TokenKind.NEWLINE]:
case cssTokens.tokens[TokenKind.RETURN]:
return finishWhitespace();
case cssTokens.tokens[TokenKind.END_OF_FILE]:
return _finishToken(TokenKind.END_OF_FILE);
case cssTokens.tokens[TokenKind.AT]:
return _finishToken(TokenKind.AT);
case cssTokens.tokens[TokenKind.DOT]:
return _finishToken(TokenKind.DOT);
case cssTokens.tokens[TokenKind.LBRACE]:
return _finishToken(TokenKind.LBRACE);
case cssTokens.tokens[TokenKind.RBRACE]:
return _finishToken(TokenKind.RBRACE);
case cssTokens.tokens[TokenKind.HASH]:
return _finishToken(TokenKind.HASH);
case cssTokens.tokens[TokenKind.COMBINATOR_PLUS]:
return _finishToken(TokenKind.COMBINATOR_PLUS);
case cssTokens.tokens[TokenKind.COMBINATOR_GREATER]:
return _finishToken(TokenKind.COMBINATOR_GREATER);
case cssTokens.tokens[TokenKind.COMBINATOR_TILDE]:
return _finishToken(TokenKind.COMBINATOR_TILDE);
case cssTokens.tokens[TokenKind.ASTERISK]:
return _finishToken(TokenKind.ASTERISK);
case cssTokens.tokens[TokenKind.NAMESPACE]:
return _finishToken(TokenKind.NAMESPACE);
case cssTokens.tokens[TokenKind.PSEUDO]:
return _finishToken(TokenKind.PSEUDO);
case cssTokens.tokens[TokenKind.COMMA]:
return _finishToken(TokenKind.COMMA);
default:
if (isIdentifierStart(ch)) {
return this.finishIdentifier();
} else if (isDigit(ch)) {
return this.finishNumber();
} else {
return _errorToken();
}
}
}
// TODO(jmesserly): we need a way to emit human readable error messages from
// the tokenizer.
lang.Token _errorToken() {
return _finishToken(TokenKind.ERROR);
}
int getIdentifierKind() {
return TokenKind.IDENTIFIER;
}
// Need to override so CSS version of isIdentifierPart is used.
lang.Token finishIdentifier() {
while (_index < _text.length) {
if (!TokenizerHelpers.isIdentifierPart(_text.charCodeAt(_index++))) {
_index--;
break;
}
}
int kind = getIdentifierKind();
if (_interpStack != null && _interpStack.depth == -1) {
_interpStack.depth = 0;
}
if (kind == TokenKind.IDENTIFIER) {
return _finishToken(TokenKind.IDENTIFIER);
} else {
return _finishToken(kind);
}
}
}
/** Static helper methods. */
class TokenizerHelpers {
static bool isIdentifierStart(int c) =>
lang.TokenizerHelpers.isIdentifierStart(c) || c == 95 /*_*/;
static bool isDigit(int c) => lang.TokenizerHelpers.isDigit(c);
static bool isHexDigit(int c) => lang.TokenizerHelpers.isHexDigit(c);
static bool isWhitespace(int c) => lang.TokenizerHelpers.isWhitespace(c);
static bool isIdentifierPart(int c) =>
lang.TokenizerHelpers.isIdentifierPart(c) || c == 45 /*-*/;
}