diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/csso/lib/parser/scanner.js | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/csso/lib/parser/scanner.js')
| -rw-r--r-- | node_modules/csso/lib/parser/scanner.js | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/node_modules/csso/lib/parser/scanner.js b/node_modules/csso/lib/parser/scanner.js new file mode 100644 index 00000000..066fa8e5 --- /dev/null +++ b/node_modules/csso/lib/parser/scanner.js @@ -0,0 +1,380 @@ +'use strict'; + +var TokenType = require('./const.js').TokenType; + +var TAB = 9; +var N = 10; +var F = 12; +var R = 13; +var SPACE = 32; +var DOUBLE_QUOTE = 34; +var QUOTE = 39; +var RIGHT_PARENTHESIS = 41; +var STAR = 42; +var SLASH = 47; +var BACK_SLASH = 92; +var UNDERSCORE = 95; +var LEFT_CURLY_BRACE = 123; +var RIGHT_CURLY_BRACE = 125; + +var WHITESPACE = 1; +var PUNCTUATOR = 2; +var DIGIT = 3; +var STRING = 4; + +var PUNCTUATION = { + 9: TokenType.Tab, // '\t' + 10: TokenType.Newline, // '\n' + 13: TokenType.Newline, // '\r' + 32: TokenType.Space, // ' ' + 33: TokenType.ExclamationMark, // '!' + 34: TokenType.QuotationMark, // '"' + 35: TokenType.NumberSign, // '#' + 36: TokenType.DollarSign, // '$' + 37: TokenType.PercentSign, // '%' + 38: TokenType.Ampersand, // '&' + 39: TokenType.Apostrophe, // '\'' + 40: TokenType.LeftParenthesis, // '(' + 41: TokenType.RightParenthesis, // ')' + 42: TokenType.Asterisk, // '*' + 43: TokenType.PlusSign, // '+' + 44: TokenType.Comma, // ',' + 45: TokenType.HyphenMinus, // '-' + 46: TokenType.FullStop, // '.' + 47: TokenType.Solidus, // '/' + 58: TokenType.Colon, // ':' + 59: TokenType.Semicolon, // ';' + 60: TokenType.LessThanSign, // '<' + 61: TokenType.EqualsSign, // '=' + 62: TokenType.GreaterThanSign, // '>' + 63: TokenType.QuestionMark, // '?' + 64: TokenType.CommercialAt, // '@' + 91: TokenType.LeftSquareBracket, // '[' + 93: TokenType.RightSquareBracket, // ']' + 94: TokenType.CircumflexAccent, // '^' + 95: TokenType.LowLine, // '_' + 123: TokenType.LeftCurlyBracket, // '{' + 124: TokenType.VerticalLine, // '|' + 125: TokenType.RightCurlyBracket, // '}' + 126: TokenType.Tilde // '~' +}; +var SYMBOL_CATEGORY_LENGTH = Math.max.apply(null, Object.keys(PUNCTUATION)) + 1; +var SYMBOL_CATEGORY = new Uint32Array(SYMBOL_CATEGORY_LENGTH); +var IS_PUNCTUATOR = new Uint32Array(SYMBOL_CATEGORY_LENGTH); + +// fill categories +Object.keys(PUNCTUATION).forEach(function(key) { + SYMBOL_CATEGORY[Number(key)] = PUNCTUATOR; + IS_PUNCTUATOR[Number(key)] = PUNCTUATOR; +}, SYMBOL_CATEGORY); + +// don't treat as punctuator +IS_PUNCTUATOR[UNDERSCORE] = 0; + +for (var i = 48; i <= 57; i++) { + SYMBOL_CATEGORY[i] = DIGIT; +} + +SYMBOL_CATEGORY[SPACE] = WHITESPACE; +SYMBOL_CATEGORY[TAB] = WHITESPACE; +SYMBOL_CATEGORY[N] = WHITESPACE; +SYMBOL_CATEGORY[R] = WHITESPACE; +SYMBOL_CATEGORY[F] = WHITESPACE; + +SYMBOL_CATEGORY[QUOTE] = STRING; +SYMBOL_CATEGORY[DOUBLE_QUOTE] = STRING; + +// +// scanner +// + +var Scanner = function(source, initBlockMode, initLine, initColumn) { + this.source = source; + + this.pos = source.charCodeAt(0) === 0xFEFF ? 1 : 0; + this.eof = this.pos === this.source.length; + this.line = typeof initLine === 'undefined' ? 1 : initLine; + this.lineStartPos = typeof initColumn === 'undefined' ? -1 : -initColumn; + + this.minBlockMode = initBlockMode ? 1 : 0; + this.blockMode = this.minBlockMode; + this.urlMode = false; + + this.prevToken = null; + this.token = null; + this.buffer = []; +}; + +Scanner.prototype = { + lookup: function(offset) { + if (offset === 0) { + return this.token; + } + + for (var i = this.buffer.length; !this.eof && i < offset; i++) { + this.buffer.push(this.getToken()); + } + + return offset <= this.buffer.length ? this.buffer[offset - 1] : null; + }, + lookupType: function(offset, type) { + var token = this.lookup(offset); + + return token !== null && token.type === type; + }, + next: function() { + var newToken = null; + + if (this.buffer.length !== 0) { + newToken = this.buffer.shift(); + } else if (!this.eof) { + newToken = this.getToken(); + } + + this.prevToken = this.token; + this.token = newToken; + + return newToken; + }, + + tokenize: function() { + var tokens = []; + + for (; this.pos < this.source.length; this.pos++) { + tokens.push(this.getToken()); + } + + return tokens; + }, + + getToken: function() { + var code = this.source.charCodeAt(this.pos); + var line = this.line; + var column = this.pos - this.lineStartPos; + var offset = this.pos; + var next; + var type; + var value; + + switch (code < SYMBOL_CATEGORY_LENGTH ? SYMBOL_CATEGORY[code] : 0) { + case DIGIT: + type = TokenType.DecimalNumber; + value = this.readDecimalNumber(); + break; + + case STRING: + type = TokenType.String; + value = this.readString(code); + break; + + case WHITESPACE: + type = TokenType.Space; + value = this.readSpaces(); + break; + + case PUNCTUATOR: + if (code === SLASH) { + next = this.pos + 1 < this.source.length ? this.source.charCodeAt(this.pos + 1) : 0; + + if (next === STAR) { // /* + type = TokenType.Comment; + value = this.readComment(); + break; + } else if (next === SLASH && !this.urlMode) { // // + if (this.blockMode > 0) { + var skip = 2; + + while (this.source.charCodeAt(this.pos + 2) === SLASH) { + skip++; + } + + type = TokenType.Identifier; + value = this.readIdentifier(skip); + + this.urlMode = this.urlMode || value === 'url'; + } else { + type = TokenType.Unknown; + value = this.readUnknown(); + } + break; + } + } + + type = PUNCTUATION[code]; + value = String.fromCharCode(code); + this.pos++; + + if (code === RIGHT_PARENTHESIS) { + this.urlMode = false; + } else if (code === LEFT_CURLY_BRACE) { + this.blockMode++; + } else if (code === RIGHT_CURLY_BRACE) { + if (this.blockMode > this.minBlockMode) { + this.blockMode--; + } + } + + break; + + default: + type = TokenType.Identifier; + value = this.readIdentifier(0); + + this.urlMode = this.urlMode || value === 'url'; + } + + this.eof = this.pos === this.source.length; + + return { + type: type, + value: value, + + offset: offset, + line: line, + column: column + }; + }, + + isNewline: function(code) { + if (code === N || code === F || code === R) { + if (code === R && this.pos + 1 < this.source.length && this.source.charCodeAt(this.pos + 1) === N) { + this.pos++; + } + + this.line++; + this.lineStartPos = this.pos; + return true; + } + + return false; + }, + + readSpaces: function() { + var start = this.pos; + + for (; this.pos < this.source.length; this.pos++) { + var code = this.source.charCodeAt(this.pos); + + if (!this.isNewline(code) && code !== SPACE && code !== TAB) { + break; + } + } + + return this.source.substring(start, this.pos); + }, + + readComment: function() { + var start = this.pos; + + for (this.pos += 2; this.pos < this.source.length; this.pos++) { + var code = this.source.charCodeAt(this.pos); + + if (code === STAR) { // */ + if (this.source.charCodeAt(this.pos + 1) === SLASH) { + this.pos += 2; + break; + } + } else { + this.isNewline(code); + } + } + + return this.source.substring(start, this.pos); + }, + + readUnknown: function() { + var start = this.pos; + + for (this.pos += 2; this.pos < this.source.length; this.pos++) { + if (this.isNewline(this.source.charCodeAt(this.pos), this.source)) { + break; + } + } + + return this.source.substring(start, this.pos); + }, + + readString: function(quote) { + var start = this.pos; + var res = ''; + + for (this.pos++; this.pos < this.source.length; this.pos++) { + var code = this.source.charCodeAt(this.pos); + + if (code === BACK_SLASH) { + var end = this.pos++; + + if (this.isNewline(this.source.charCodeAt(this.pos), this.source)) { + res += this.source.substring(start, end); + start = this.pos + 1; + } + } else if (code === quote) { + this.pos++; + break; + } + } + + return res + this.source.substring(start, this.pos); + }, + + readDecimalNumber: function() { + var start = this.pos; + var code; + + for (this.pos++; this.pos < this.source.length; this.pos++) { + code = this.source.charCodeAt(this.pos); + + if (code < 48 || code > 57) { // 0 .. 9 + break; + } + } + + return this.source.substring(start, this.pos); + }, + + readIdentifier: function(skip) { + var start = this.pos; + + for (this.pos += skip; this.pos < this.source.length; this.pos++) { + var code = this.source.charCodeAt(this.pos); + + if (code === BACK_SLASH) { + this.pos++; + + // skip escaped unicode sequence that can ends with space + // [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? + for (var i = 0; i < 7 && this.pos + i < this.source.length; i++) { + code = this.source.charCodeAt(this.pos + i); + + if (i !== 6) { + if ((code >= 48 && code <= 57) || // 0 .. 9 + (code >= 65 && code <= 70) || // A .. F + (code >= 97 && code <= 102)) { // a .. f + continue; + } + } + + if (i > 0) { + this.pos += i - 1; + if (code === SPACE || code === TAB || this.isNewline(code)) { + this.pos++; + } + } + + break; + } + } else if (code < SYMBOL_CATEGORY_LENGTH && + IS_PUNCTUATOR[code] === PUNCTUATOR) { + break; + } + } + + return this.source.substring(start, this.pos); + } +}; + +// warm up tokenizer to elimitate code branches that never execute +// fix soft deoptimizations (insufficient type feedback) +new Scanner('\n\r\r\n\f//""\'\'/**/1a;.{url(a)}').lookup(1e3); + +module.exports = Scanner; |
