123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- var cmpChar = require('../../tokenizer').cmpChar;
- var isNumber = require('../../tokenizer').isNumber;
- var TYPE = require('../../tokenizer').TYPE;
- var IDENTIFIER = TYPE.Identifier;
- var NUMBER = TYPE.Number;
- var PLUSSIGN = TYPE.PlusSign;
- var HYPHENMINUS = TYPE.HyphenMinus;
- var N = 110; // 'n'.charCodeAt(0)
- var DISALLOW_SIGN = true;
- var ALLOW_SIGN = false;
- function checkTokenIsInteger(scanner, disallowSign) {
- var pos = scanner.tokenStart;
- if (scanner.source.charCodeAt(pos) === PLUSSIGN ||
- scanner.source.charCodeAt(pos) === HYPHENMINUS) {
- if (disallowSign) {
- scanner.error();
- }
- pos++;
- }
- for (; pos < scanner.tokenEnd; pos++) {
- if (!isNumber(scanner.source.charCodeAt(pos))) {
- scanner.error('Unexpected input', pos);
- }
- }
- }
- // An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
- module.exports = {
- name: 'AnPlusB',
- structure: {
- a: [String, null],
- b: [String, null]
- },
- parse: function() {
- var start = this.scanner.tokenStart;
- var end = start;
- var prefix = '';
- var a = null;
- var b = null;
- if (this.scanner.tokenType === NUMBER ||
- this.scanner.tokenType === PLUSSIGN) {
- checkTokenIsInteger(this.scanner, ALLOW_SIGN);
- prefix = this.scanner.getTokenValue();
- this.scanner.next();
- end = this.scanner.tokenStart;
- }
- if (this.scanner.tokenType === IDENTIFIER) {
- var bStart = this.scanner.tokenStart;
- if (cmpChar(this.scanner.source, bStart, HYPHENMINUS)) {
- if (prefix === '') {
- prefix = '-';
- bStart++;
- } else {
- this.scanner.error('Unexpected hyphen minus');
- }
- }
- if (!cmpChar(this.scanner.source, bStart, N)) {
- this.scanner.error();
- }
- a = prefix === '' ? '1' :
- prefix === '+' ? '+1' :
- prefix === '-' ? '-1' :
- prefix;
- var len = this.scanner.tokenEnd - bStart;
- if (len > 1) {
- // ..n-..
- if (this.scanner.source.charCodeAt(bStart + 1) !== HYPHENMINUS) {
- this.scanner.error('Unexpected input', bStart + 1);
- }
- if (len > 2) {
- // ..n-{number}..
- this.scanner.tokenStart = bStart + 2;
- } else {
- // ..n- {number}
- this.scanner.next();
- this.scanner.skipSC();
- }
- checkTokenIsInteger(this.scanner, DISALLOW_SIGN);
- b = '-' + this.scanner.getTokenValue();
- this.scanner.next();
- end = this.scanner.tokenStart;
- } else {
- prefix = '';
- this.scanner.next();
- end = this.scanner.tokenStart;
- this.scanner.skipSC();
- if (this.scanner.tokenType === HYPHENMINUS ||
- this.scanner.tokenType === PLUSSIGN) {
- prefix = this.scanner.getTokenValue();
- this.scanner.next();
- this.scanner.skipSC();
- }
- if (this.scanner.tokenType === NUMBER) {
- checkTokenIsInteger(this.scanner, prefix !== '');
- if (!isNumber(this.scanner.source.charCodeAt(this.scanner.tokenStart))) {
- prefix = this.scanner.source.charAt(this.scanner.tokenStart);
- this.scanner.tokenStart++;
- }
- if (prefix === '') {
- // should be an operator before number
- this.scanner.error();
- } else if (prefix === '+') {
- // plus is using by default
- prefix = '';
- }
- b = prefix + this.scanner.getTokenValue();
- this.scanner.next();
- end = this.scanner.tokenStart;
- } else {
- if (prefix) {
- this.scanner.eat(NUMBER);
- }
- }
- }
- } else {
- if (prefix === '' || prefix === '+') { // no number
- this.scanner.error(
- 'Number or identifier is expected',
- this.scanner.tokenStart + (
- this.scanner.tokenType === PLUSSIGN ||
- this.scanner.tokenType === HYPHENMINUS
- )
- );
- }
- b = prefix;
- }
- return {
- type: 'AnPlusB',
- loc: this.getLocation(start, end),
- a: a,
- b: b
- };
- },
- generate: function(node) {
- var a = node.a !== null && node.a !== undefined;
- var b = node.b !== null && node.b !== undefined;
- if (a) {
- this.chunk(
- node.a === '+1' ? '+n' :
- node.a === '1' ? 'n' :
- node.a === '-1' ? '-n' :
- node.a + 'n'
- );
- if (b) {
- b = String(node.b);
- if (b.charAt(0) === '-' || b.charAt(0) === '+') {
- this.chunk(b.charAt(0));
- this.chunk(b.substr(1));
- } else {
- this.chunk('+');
- this.chunk(b);
- }
- }
- } else {
- this.chunk(String(node.b));
- }
- }
- };
|