| Index: pkg/csslib/lib/src/tokenizer_base.dart
|
| diff --git a/utils/css/tokenizer_base.dart b/pkg/csslib/lib/src/tokenizer_base.dart
|
| similarity index 74%
|
| copy from utils/css/tokenizer_base.dart
|
| copy to pkg/csslib/lib/src/tokenizer_base.dart
|
| index f98f245f910dcbfc2ba12681521bf31d70766dab..f33a3629ceee9f7c465d8677da9d40daefc27e47 100644
|
| --- a/utils/css/tokenizer_base.dart
|
| +++ b/pkg/csslib/lib/src/tokenizer_base.dart
|
| @@ -1,54 +1,58 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2012, 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.
|
| // Generated by scripts/tokenizer_gen.py.
|
|
|
| +part of csslib.parser;
|
|
|
| -abstract class TokenSource {
|
| - Token next();
|
| -}
|
| -
|
| -class InterpStack {
|
| - InterpStack next, previous;
|
| - final int quote;
|
| - final bool isMultiline;
|
| - int depth;
|
| -
|
| - InterpStack(this.previous, this.quote, this.isMultiline): depth = -1;
|
| -
|
| - InterpStack pop() {
|
| - return this.previous;
|
| - }
|
| +/** Tokenizer state to support look ahead for Less' nested selectors. */
|
| +class TokenizerState {
|
| + final int index;
|
| + final int startIndex;
|
| + final bool selectorExpression;
|
|
|
| - static InterpStack push(InterpStack stack, int quote, bool isMultiline) {
|
| - var newStack = new InterpStack(stack, quote, isMultiline);
|
| - if (stack != null) newStack.previous = stack;
|
| - return newStack;
|
| - }
|
| + TokenizerState(TokenizerBase base) :
|
| + this.index = base._index,
|
| + this.startIndex = base._startIndex,
|
| + this.selectorExpression = base.selectorExpression;
|
| }
|
|
|
| /**
|
| * The base class for our tokenizer. The hand coded parts are in this file, with
|
| * the generated parts in the subclass Tokenizer.
|
| */
|
| -class CSSTokenizerBase implements TokenSource {
|
| - final SourceFile _source;
|
| +abstract class TokenizerBase {
|
| + final SourceFile _file;
|
| final bool _skipWhitespace;
|
| - String _text;
|
| + final String _text;
|
| +
|
| + /**
|
| + * Changes tokenization when in a pseudo function expression. If true then
|
| + * minus signs are handled as operators instead of identifiers.
|
| + */
|
| + bool selectorExpression = false;
|
|
|
| int _index;
|
| int _startIndex;
|
|
|
| - /** Keeps track of string interpolation state. */
|
| - InterpStack _interpStack;
|
| + static const String _CDATA_START = '<![CDATA[';
|
| + static const String _CDATA_END = ']]>';
|
|
|
| - CSSTokenizerBase(this._source, this._skipWhitespace, [index = 0])
|
| - : this._index = index {
|
| - _text = _source.text;
|
| - }
|
| + TokenizerBase(this._file, this._text, this._skipWhitespace,
|
| + [this._index = 0]);
|
| +
|
| + Token next();
|
| + int getIdentifierKind();
|
| +
|
| + /** Snapshot of Tokenizer scanning state. */
|
| + TokenizerState get mark => new TokenizerState(this);
|
|
|
| - abstract Token next();
|
| - abstract int getIdentifierKind();
|
| + /** Restore Tokenizer scanning state. */
|
| + void restore(TokenizerState markedData) {
|
| + _index = markedData.index;
|
| + _startIndex = markedData.startIndex;
|
| + selectorExpression = markedData.selectorExpression;
|
| + }
|
|
|
| int _nextChar() {
|
| if (_index < _text.length) {
|
| @@ -88,21 +92,23 @@ class CSSTokenizerBase implements TokenSource {
|
| }
|
|
|
| Token _finishToken(int kind) {
|
| - return new Token(kind, _source, _startIndex, _index);
|
| + return new Token(kind, _file.span(_startIndex, _index));
|
| }
|
|
|
| Token _errorToken([String message = null]) {
|
| return new ErrorToken(
|
| - TokenKind.ERROR, _source, _startIndex, _index, message);
|
| + TokenKind.ERROR, _file.span(_startIndex, _index), message);
|
| }
|
|
|
| Token finishWhitespace() {
|
| _index--;
|
| while (_index < _text.length) {
|
| final ch = _text.codeUnitAt(_index++);
|
| - if (ch == 32/*' '*/ || ch == 9/*'\t'*/ || ch == 13/*'\r'*/) {
|
| + if (ch == TokenChar.SPACE ||
|
| + ch == TokenChar.TAB ||
|
| + ch == TokenChar.RETURN) {
|
| // do nothing
|
| - } else if (ch == 10/*'\n'*/) {
|
| + } else if (ch == TokenChar.NEWLINE) {
|
| if (!_skipWhitespace) {
|
| return _finishToken(TokenKind.WHITESPACE); // note the newline?
|
| }
|
| @@ -122,7 +128,7 @@ class CSSTokenizerBase implements TokenSource {
|
| Token finishSingleLineComment() {
|
| while (true) {
|
| int ch = _nextChar();
|
| - if (ch == 0 || ch == 10/*'\n'*/ || ch == 13/*'\r'*/) {
|
| + if (ch == 0 || ch == TokenChar.NEWLINE || ch == TokenChar.RETURN) {
|
| if (_skipWhitespace) {
|
| return next();
|
| } else {
|
| @@ -138,12 +144,12 @@ class CSSTokenizerBase implements TokenSource {
|
| int ch = _nextChar();
|
| if (ch == 0) {
|
| return _errorToken();
|
| - } else if (ch == 42/*'*'*/) {
|
| - if (_maybeEatChar(47/*'/'*/)) {
|
| + } else if (ch == TokenChar.ASTERISK) {
|
| + if (_maybeEatChar(TokenChar.SLASH)) {
|
| nesting--;
|
| }
|
| - } else if (ch == 47/*'/'*/) {
|
| - if (_maybeEatChar(42/*'*'*/)) {
|
| + } else if (ch == TokenChar.SLASH) {
|
| + if (_maybeEatChar(TokenChar.ASTERISK)) {
|
| nesting++;
|
| }
|
| }
|
| @@ -212,7 +218,7 @@ class CSSTokenizerBase implements TokenSource {
|
| Token finishNumber() {
|
| eatDigits();
|
|
|
| - if (_peekChar() == 46/*.*/) {
|
| + if (_peekChar() == TokenChar.DOT) {
|
| // Handle the case of 1.toString().
|
| _nextChar();
|
| if (TokenizerHelpers.isDigit(_peekChar())) {
|
| @@ -229,8 +235,8 @@ class CSSTokenizerBase implements TokenSource {
|
| Token finishNumberExtra(int kind) {
|
| if (_maybeEatChar(101/*e*/) || _maybeEatChar(69/*E*/)) {
|
| kind = TokenKind.DOUBLE;
|
| - _maybeEatChar(45/*-*/);
|
| - _maybeEatChar(43/*+*/);
|
| + _maybeEatChar(TokenKind.MINUS);
|
| + _maybeEatChar(TokenKind.PLUS);
|
| eatDigits();
|
| }
|
| if (_peekChar() != 0 && TokenizerHelpers.isIdentifierStart(_peekChar())) {
|
| @@ -244,20 +250,26 @@ class CSSTokenizerBase implements TokenSource {
|
| Token _makeStringToken(List<int> buf, bool isPart) {
|
| final s = new String.fromCharCodes(buf);
|
| final kind = isPart ? TokenKind.STRING_PART : TokenKind.STRING;
|
| - return new LiteralToken(kind, _source, _startIndex, _index, s);
|
| + return new LiteralToken(kind, _file.span(_startIndex, _index), s);
|
| + }
|
| +
|
| + Token makeIEFilter(int start, int end) {
|
| + var filter = _text.substring(start, end);
|
| + return new LiteralToken(TokenKind.STRING, _file.span(start, end), filter);
|
| }
|
|
|
| Token _makeRawStringToken(bool isMultiline) {
|
| - String s;
|
| + var s;
|
| if (isMultiline) {
|
| // Skip initial newline in multiline strings
|
| int start = _startIndex + 4;
|
| - if (_source.text[start] == '\n') start++;
|
| - s = _source.text.substring(start, _index - 3);
|
| + if (_text[start] == '\n') start++;
|
| + s = _text.substring(start, _index - 3);
|
| } else {
|
| - s = _source.text.substring(_startIndex + 2, _index - 1);
|
| + s = _text.substring(_startIndex + 2, _index - 1);
|
| }
|
| - return new LiteralToken(TokenKind.STRING, _source, _startIndex, _index, s);
|
| + return new LiteralToken(TokenKind.STRING,
|
| + _file.span(_startIndex, _index), s);
|
| }
|
|
|
| Token finishMultilineString(int quote) {
|
| @@ -274,11 +286,7 @@ class CSSTokenizerBase implements TokenSource {
|
| buf.add(quote);
|
| }
|
| buf.add(quote);
|
| - } else if (ch == 36/*$*/) {
|
| - // start of string interp
|
| - _interpStack = InterpStack.push(_interpStack, quote, true);
|
| - return _makeStringToken(buf, true);
|
| - } else if (ch == 92/*\*/) {
|
| + } else if (ch == TokenChar.BACKSLASH) {
|
| var escapeVal = readEscapeSequence();
|
| if (escapeVal == -1) {
|
| return _errorToken("invalid hex escape sequence");
|
| @@ -292,22 +300,10 @@ class CSSTokenizerBase implements TokenSource {
|
| }
|
|
|
| Token _finishOpenBrace() {
|
| - if (_interpStack != null) {
|
| - if (_interpStack.depth == -1) {
|
| - _interpStack.depth = 1;
|
| - } else {
|
| - assert(_interpStack.depth >= 0);
|
| - _interpStack.depth += 1;
|
| - }
|
| - }
|
| return _finishToken(TokenKind.LBRACE);
|
| }
|
|
|
| Token _finishCloseBrace() {
|
| - if (_interpStack != null) {
|
| - _interpStack.depth -= 1;
|
| - assert(_interpStack.depth >= 0);
|
| - }
|
| return _finishToken(TokenKind.RBRACE);
|
| }
|
|
|
| @@ -315,7 +311,7 @@ class CSSTokenizerBase implements TokenSource {
|
| if (_maybeEatChar(quote)) {
|
| if (_maybeEatChar(quote)) {
|
| // skip an initial newline
|
| - _maybeEatChar(10/*'\n'*/);
|
| + _maybeEatChar(TokenChar.NEWLINE);
|
| return finishMultilineString(quote);
|
| } else {
|
| return _makeStringToken(new List<int>(), false);
|
| @@ -359,13 +355,9 @@ class CSSTokenizerBase implements TokenSource {
|
| int ch = _nextChar();
|
| if (ch == quote) {
|
| return _makeStringToken(buf, false);
|
| - } else if (ch == 36/*$*/) {
|
| - // start of string interp
|
| - _interpStack = InterpStack.push(_interpStack, quote, false);
|
| - return _makeStringToken(buf, true);
|
| } else if (ch == 0) {
|
| return _errorToken();
|
| - } else if (ch == 92/*\*/) {
|
| + } else if (ch == TokenChar.BACKSLASH) {
|
| var escapeVal = readEscapeSequence();
|
| if (escapeVal == -1) {
|
| return _errorToken("invalid hex escape sequence");
|
| @@ -383,32 +375,30 @@ class CSSTokenizerBase implements TokenSource {
|
| int hexValue;
|
| switch (ch) {
|
| case 110/*n*/:
|
| - return 0x0a/*'\n'*/;
|
| + return TokenChar.NEWLINE;
|
| case 114/*r*/:
|
| - return 0x0d/*'\r'*/;
|
| + return TokenChar.RETURN;
|
| case 102/*f*/:
|
| - return 0x0c/*'\f'*/;
|
| + return TokenChar.FF;
|
| case 98/*b*/:
|
| - return 0x08/*'\b'*/;
|
| + return TokenChar.BACKSPACE;
|
| case 116/*t*/:
|
| - return 0x09/*'\t'*/;
|
| + return TokenChar.TAB;
|
| case 118/*v*/:
|
| - return 0x0b/*'\v'*/;
|
| + return TokenChar.FF;
|
| case 120/*x*/:
|
| hexValue = readHex(2);
|
| break;
|
| case 117/*u*/:
|
| - if (_maybeEatChar(123/*{*/)) {
|
| + if (_maybeEatChar(TokenChar.LBRACE)) {
|
| hexValue = readHex();
|
| - if (!_maybeEatChar(125/*}*/)) {
|
| + if (!_maybeEatChar(TokenChar.RBRACE)) {
|
| return -1;
|
| - } else {
|
| - break;
|
| }
|
| } else {
|
| hexValue = readHex(4);
|
| - break;
|
| }
|
| + break;
|
| default: return ch;
|
| }
|
|
|
| @@ -420,7 +410,8 @@ class CSSTokenizerBase implements TokenSource {
|
| if (hexValue < 0xD800 || hexValue > 0xDFFF && hexValue <= 0xFFFF) {
|
| return hexValue;
|
| } else if (hexValue <= 0x10FFFF){
|
| - world.fatal('unicode values greater than 2 bytes not implemented yet');
|
| + messages.error('unicode values greater than 2 bytes not implemented yet',
|
| + _file.span(_startIndex, _startIndex + 1));
|
| return -1;
|
| } else {
|
| return -1;
|
|
|