Ver código fonte

moved functions in upper scope

Gildas 7 anos atrás
pai
commit
32d634e1f3
1 arquivos alterados com 406 adições e 404 exclusões
  1. 406 404
      lib/single-file/css-declarations-parser.js

+ 406 - 404
lib/single-file/css-declarations-parser.js

@@ -91,6 +91,408 @@ this.parseCss = this.parseCss || (() => {
 		return String.fromCharCode(lead) + String.fromCharCode(trail);
 	}
 
+	function consumeAToken(consume, next, eof, reconsume, parseerror, donothing) {
+		consumeComments(consume, next, eof, parseerror);
+		let code = consume();
+		if (whitespace(code)) {
+			while (whitespace(next())) code = consume();
+			return new Token(WHITESPACE_TOKEN_TYPE);
+		}
+		else if (code == 0x22) return consumeAStringToken(consume, next, eof, reconsume, parseerror, donothing, code);
+		else if (code == 0x23) {
+			if (namechar(next()) || areAValidEscape(next(1), next(2))) {
+				const token = new Token(HASH_TOKEN_TYPE);
+				if (wouldStartAnIdentifier(next(1), next(2), next(3))) token.type = "id";
+				token.value = consumeAName(consume, next, eof, reconsume);
+				return token;
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x24) {
+			if (next() == 0x3d) {
+				code = consume();
+				return new Token(SUFFIX_MATCH_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x27) return consumeAStringToken(consume, next, eof, reconsume, parseerror, donothing, code);
+		else if (code == 0x28) return new Token(OPEN_PAREN_TOKEN_TYPE);
+		else if (code == 0x29) return new Token(CLOSE_PAREN_TOKEN_TYPE);
+		else if (code == 0x2a) {
+			if (next() == 0x3d) {
+				code = consume();
+				return new Token(SUBSTRING_MATCH_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x2b) {
+			if (startsWithANumber(next, code)) {
+				reconsume();
+				return consumeANumericToken(consume, next, eof, reconsume);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x2c) return new Token(COMMA_TOKEN_TYPE);
+		else if (code == 0x2d) {
+			if (startsWithANumber(next, code)) {
+				reconsume();
+				return consumeANumericToken(consume, next, eof, reconsume);
+			} else if (next(1) == 0x2d && next(2) == 0x3e) {
+				consume(2);
+				return new Token(CDC_TOKEN_TYPE);
+			} else if (wouldStartAnIdentifier(code, next(1), next(2))) {
+				reconsume();
+				return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x2e) {
+			if (startsWithANumber(next, code)) {
+				reconsume();
+				return consumeANumericToken(consume, next, eof, reconsume);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x3a) return new Token(COLON_TOKEN_TYPE);
+		else if (code == 0x3b) return new Token(SEMICOLON_TOKEN_TYPE);
+		else if (code == 0x3c) {
+			if (next(1) == 0x21 && next(2) == 0x2d && next(3) == 0x2d) {
+				consume(3);
+				return new Token(CDO_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x40) {
+			return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+		}
+		else if (code == 0x5b) new Token(OPEN_SQUARE_TOKEN_TYPE);
+		else if (code == 0x5c) {
+			if (startsWithAValidEscape(next, code)) {
+				reconsume();
+				return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
+			} else {
+				parseerror();
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x5d) new Token(CLOSE_SQUARE_TOKEN_TYPE);
+		else if (code == 0x5e) {
+			if (next() == 0x3d) {
+				code = consume();
+				return new Token(PREFIX_MATCH_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x7b) return new Token(OPEN_CURLY_TOKEN_TYPE);
+		else if (code == 0x7c) {
+			if (next() == 0x3d) {
+				code = consume();
+				return new Token(DASH_MATCH_TOKEN_TYPE);
+			} else if (next() == 0x7c) {
+				code = consume();
+				return new Token(COLUMN_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (code == 0x7d) return new Token(CLOSE_CURLY_TOKEN_TYPE);
+		else if (code == 0x7e) {
+			if (next() == 0x3d) {
+				code = consume();
+				return new Token(INCLUDE_MATCH_TOKEN_TYPE);
+			} else {
+				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+			}
+		}
+		else if (digit(code)) {
+			reconsume();
+			return consumeANumericToken(consume, next, eof, reconsume);
+		}
+		else if (namestartchar(code)) {
+			reconsume();
+			return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
+		}
+		else if (eof()) return new Token(EOF_TOKEN_TYPE);
+		else return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
+	}
+
+	function consumeComments(consume, next, eof, parseerror) {
+		while (next(1) == 0x2f && next(2) == 0x2a) {
+			consume(2);
+			while (true) { // eslint-disable-line no-constant-condition
+				let code = consume();
+				if (code == 0x2a && next() == 0x2f) {
+					code = consume();
+					break;
+				} else if (eof()) {
+					parseerror();
+					return;
+				}
+			}
+		}
+	}
+
+	function consumeANumericToken(consume, next, eof, reconsume) {
+		const num = consumeANumber(consume, next);
+		if (wouldStartAnIdentifier(next(1), next(2), next(3))) {
+			const token = new Token(DIMENSION_TOKEN_TYPE, num.value);
+			token.repr = num.repr;
+			token.type = num.type;
+			token.unit = consumeAName(consume, next, eof, reconsume);
+			return token;
+		} else if (next() == 0x25) {
+			consume();
+			const token = new Token(PERCENTAGE_TOKEN_TYPE, num.value);
+			token.repr = num.repr;
+			return token;
+		} else {
+			const token = new Token(NUMBER_TOKEN_TYPE, num.value);
+			token.type = "integer";
+			token.repr = num.repr;
+			token.type = num.type;
+			return token;
+		}
+	}
+
+	function consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing) {
+		const str = consumeAName(consume, next, eof, reconsume);
+		if (str.toLowerCase() == "url" && next() == 0x28) {
+			consume();
+			while (whitespace(next(1)) && whitespace(next(2))) consume();
+			if (next() == 0x22 || next() == 0x27) {
+				return new Token(FUNCTION_TOKEN_TYPE, str);
+			} else if (whitespace(next()) && (next(2) == 0x22 || next(2) == 0x27)) {
+				return new Token(FUNCTION_TOKEN_TYPE, str);
+			} else {
+				return consumeAURLToken(consume, next, eof, parseerror, donothing);
+			}
+		} else if (next() == 0x28) {
+			consume();
+			return new Token(FUNCTION_TOKEN_TYPE, str);
+		} else {
+			return new Token(IDENT_TOKEN_TYPE, str);
+		}
+	}
+
+	function consumeAStringToken(consume, next, eof, reconsume, parseerror, donothing, code) {
+		const endingCodePoint = code;
+		let string = "";
+		while (code = consume()) { // eslint-disable-line no-cond-assign
+			if (code == endingCodePoint || eof()) {
+				return new Token(STRING_TOKEN_TYPE, string);
+			} else if (newline(code)) {
+				parseerror();
+				reconsume();
+				return new Token(BAD_STRING_TOKEN_TYPE);
+			} else if (code == 0x5c) {
+				if (eof(next())) {
+					donothing();
+				} else if (newline(next())) {
+					code = consume();
+				} else {
+					string += stringFromCode(consumeEscape(consume, next, eof));
+				}
+			} else {
+				string += stringFromCode(code);
+			}
+		}
+	}
+
+	function consumeAURLToken(consume, next, eof, parseerror, donothing) {
+		const token = new Token(URL_TOKEN_TYPE, "");
+		while (whitespace(next())) consume();
+		if (eof(next())) return token;
+		let code;
+		while (code = consume()) { // eslint-disable-line no-cond-assign
+			if (code == 0x29 || eof()) {
+				return token;
+			} else if (whitespace(code)) {
+				while (whitespace(next())) code = consume();
+				if (next() == 0x29 || eof(next())) {
+					code = consume();
+					return token;
+				} else {
+					consumeTheRemnantsOfABadURL(consume, next, eof, donothing);
+					return new Token(BAD_URL_TOKEN_TYPE);
+				}
+			} else if (code == 0x22 || code == 0x27 || code == 0x28 || nonprintable(code)) {
+				parseerror();
+				consumeTheRemnantsOfABadURL(consume, next, eof, donothing);
+				return new Token(BAD_URL_TOKEN_TYPE);
+			} else if (code == 0x5c) {
+				if (startsWithAValidEscape(next, code)) {
+					token.value += stringFromCode(consumeEscape(consume, next, eof));
+				} else {
+					parseerror();
+					consumeTheRemnantsOfABadURL(consume, next, eof, donothing);
+					return new Token(BAD_URL_TOKEN_TYPE);
+				}
+			} else {
+				token.value += stringFromCode(code);
+			}
+		}
+	}
+
+	function consumeEscape(consume, next, eof) {
+		// Assume the the current character is the \
+		// and the next code point is not a newline.
+		let code = consume();
+		if (hexdigit(code)) {
+			// Consume 1-6 hex digits
+			const digits = [code];
+			for (let total = 0; total < 5; total++) {
+				if (hexdigit(next())) {
+					code = consume();
+					digits.push(code);
+				} else {
+					break;
+				}
+			}
+			if (whitespace(next())) code = consume();
+			let value = parseInt(digits.map(function (x) { return String.fromCharCode(x); }).join(""), 16);
+			if (value > maximumallowedcodepoint) value = 0xfffd;
+			return value;
+		} else if (eof()) {
+			return 0xfffd;
+		} else {
+			return code;
+		}
+	}
+
+	function areAValidEscape(c1, c2) {
+		if (c1 != 0x5c) return false;
+		if (newline(c2)) return false;
+		return true;
+	}
+
+	function startsWithAValidEscape(next, code) {
+		return areAValidEscape(code, next());
+	}
+
+	function wouldStartAnIdentifier(c1, c2, c3) {
+		if (c1 == 0x2d) {
+			return namestartchar(c2) || c2 == 0x2d || areAValidEscape(c2, c3);
+		} else if (namestartchar(c1)) {
+			return true;
+		} else if (c1 == 0x5c) {
+			return areAValidEscape(c1, c2);
+		} else {
+			return false;
+		}
+	}
+
+	function wouldStartANumber(c1, c2, c3) {
+		if (c1 == 0x2b || c1 == 0x2d) {
+			if (digit(c2)) return true;
+			if (c2 == 0x2e && digit(c3)) return true;
+			return false;
+		} else if (c1 == 0x2e) {
+			if (digit(c2)) return true;
+			return false;
+		} else if (digit(c1)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	function startsWithANumber(next, code) {
+		return wouldStartANumber(code, next(1), next(2));
+	}
+
+	function consumeAName(consume, next, eof, reconsume) {
+		let result = "";
+		let code;
+		while (code = consume()) { // eslint-disable-line no-cond-assign
+			if (namechar(code)) {
+				result += stringFromCode(code);
+			} else if (startsWithAValidEscape(next, code)) {
+				result += stringFromCode(consumeEscape(consume, next, eof));
+			} else {
+				reconsume();
+				return result;
+			}
+		}
+	}
+
+	function consumeANumber(consume, next) {
+		let repr = [];
+		let type = "integer";
+		let code;
+		if (next() == 0x2b || next() == 0x2d) {
+			code = consume();
+			repr += stringFromCode(code);
+		}
+		while (digit(next())) {
+			code = consume();
+			repr += stringFromCode(code);
+		}
+		if (next(1) == 0x2e && digit(next(2))) {
+			code = consume();
+			repr += stringFromCode(code);
+			code = consume();
+			repr += stringFromCode(code);
+			type = "number";
+			while (digit(next())) {
+				code = consume();
+				repr += stringFromCode(code);
+			}
+		}
+		const c1 = next(1), c2 = next(2), c3 = next(3);
+		if ((c1 == 0x45 || c1 == 0x65) && digit(c2)) {
+			code = consume();
+			repr += stringFromCode(code);
+			code = consume();
+			repr += stringFromCode(code);
+			type = "number";
+			while (digit(next())) {
+				code = consume();
+				repr += stringFromCode(code);
+			}
+		} else if ((c1 == 0x45 || c1 == 0x65) && (c2 == 0x2b || c2 == 0x2d) && digit(c3)) {
+			code = consume();
+			repr += stringFromCode(code);
+			code = consume();
+			repr += stringFromCode(code);
+			code = consume();
+			repr += stringFromCode(code);
+			type = "number";
+			while (digit(next())) {
+				code = consume();
+				repr += stringFromCode(code);
+			}
+		}
+		const value = convertAStringToANumber(repr);
+		return { type: type, value: value, repr: repr };
+	}
+
+	function convertAStringToANumber(string) {
+		// CSS's number rules are identical to JS, afaik.
+		return Number(string);
+	}
+
+	function consumeTheRemnantsOfABadURL(consume, next, eof, donothing) {
+		let code;
+		while (code = consume()) { // eslint-disable-line no-cond-assign
+			if (code == 0x29 || eof()) {
+				return;
+			} else if (startsWithAValidEscape(next, code)) {
+				consumeEscape(consume, next, eof);
+				donothing();
+			} else {
+				donothing();
+			}
+		}
+	}
+
 	function tokenize(str) {
 		str = preprocess(str);
 		let i = -1;
@@ -100,6 +502,7 @@ this.parseCss = this.parseCss || (() => {
 		// Line number information.
 		let line = 0;
 		let column = 0;
+
 		// The only use of lastLineLength is in reconsume().
 		let lastLineLength = 0;
 		const incrLineno = function () {
@@ -126,11 +529,11 @@ this.parseCss = this.parseCss || (() => {
 			if (num === undefined)
 				num = 1;
 			i += num;
-			code = codepoint(i);
+			const code = codepoint(i);
 			if (newline(code)) incrLineno();
 			else column += num;
 			//console.log('Consume '+i+' '+String.fromCharCode(code) + ' 0x' + code.toString(16));
-			return true;
+			return code;
 		};
 		const reconsume = function () {
 			i -= 1;
@@ -151,410 +554,9 @@ this.parseCss = this.parseCss || (() => {
 		const donothing = function () { };
 		const parseerror = function () { throw new Error("Parse error at index " + i + ", processing codepoint 0x" + code.toString(16) + "."); };
 
-		const consumeAToken = function () {
-			consumeComments();
-			consume();
-			if (whitespace(code)) {
-				while (whitespace(next())) consume();
-				return new Token(WHITESPACE_TOKEN_TYPE);
-			}
-			else if (code == 0x22) return consumeAStringToken();
-			else if (code == 0x23) {
-				if (namechar(next()) || areAValidEscape(next(1), next(2))) {
-					const token = new Token(HASH_TOKEN_TYPE);
-					if (wouldStartAnIdentifier(next(1), next(2), next(3))) token.type = "id";
-					token.value = consumeAName();
-					return token;
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x24) {
-				if (next() == 0x3d) {
-					consume();
-					return new Token(SUFFIX_MATCH_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x27) return consumeAStringToken();
-			else if (code == 0x28) return new Token(OPEN_PAREN_TOKEN_TYPE);
-			else if (code == 0x29) return new Token(CLOSE_PAREN_TOKEN_TYPE);
-			else if (code == 0x2a) {
-				if (next() == 0x3d) {
-					consume();
-					return new Token(SUBSTRING_MATCH_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x2b) {
-				if (startsWithANumber()) {
-					reconsume();
-					return consumeANumericToken();
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x2c) return new Token(COMMA_TOKEN_TYPE);
-			else if (code == 0x2d) {
-				if (startsWithANumber()) {
-					reconsume();
-					return consumeANumericToken();
-				} else if (next(1) == 0x2d && next(2) == 0x3e) {
-					consume(2);
-					return new Token(CDC_TOKEN_TYPE);
-				} else if (startsWithAnIdentifier()) {
-					reconsume();
-					return consumeAnIdentlikeToken();
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x2e) {
-				if (startsWithANumber()) {
-					reconsume();
-					return consumeANumericToken();
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x3a) return new Token(COLON_TOKEN_TYPE);
-			else if (code == 0x3b) return new Token(SEMICOLON_TOKEN_TYPE);
-			else if (code == 0x3c) {
-				if (next(1) == 0x21 && next(2) == 0x2d && next(3) == 0x2d) {
-					consume(3);
-					return new Token(CDO_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x40) {
-				return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-			}
-			else if (code == 0x5b) new Token(OPEN_SQUARE_TOKEN_TYPE);
-			else if (code == 0x5c) {
-				if (startsWithAValidEscape()) {
-					reconsume();
-					return consumeAnIdentlikeToken();
-				} else {
-					parseerror();
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x5d) new Token(CLOSE_SQUARE_TOKEN_TYPE);
-			else if (code == 0x5e) {
-				if (next() == 0x3d) {
-					consume();
-					return new Token(PREFIX_MATCH_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x7b) return new Token(OPEN_CURLY_TOKEN_TYPE);
-			else if (code == 0x7c) {
-				if (next() == 0x3d) {
-					consume();
-					return new Token(DASH_MATCH_TOKEN_TYPE);
-				} else if (next() == 0x7c) {
-					consume();
-					return new Token(COLUMN_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (code == 0x7d) return new Token(CLOSE_CURLY_TOKEN_TYPE);
-			else if (code == 0x7e) {
-				if (next() == 0x3d) {
-					consume();
-					return new Token(INCLUDE_MATCH_TOKEN_TYPE);
-				} else {
-					return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-				}
-			}
-			else if (digit(code)) {
-				reconsume();
-				return consumeANumericToken();
-			}
-			else if (namestartchar(code)) {
-				reconsume();
-				return consumeAnIdentlikeToken();
-			}
-			else if (eof()) return new Token(EOF_TOKEN_TYPE);
-			else return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
-		};
-
-		const consumeComments = function () {
-			while (next(1) == 0x2f && next(2) == 0x2a) {
-				consume(2);
-				while (true) { // eslint-disable-line no-constant-condition
-					consume();
-					if (code == 0x2a && next() == 0x2f) {
-						consume();
-						break;
-					} else if (eof()) {
-						parseerror();
-						return;
-					}
-				}
-			}
-		};
-
-		const consumeANumericToken = function () {
-			const num = consumeANumber();
-			if (wouldStartAnIdentifier(next(1), next(2), next(3))) {
-				const token = new Token(DIMENSION_TOKEN_TYPE, num.value);
-				token.repr = num.repr;
-				token.type = num.type;
-				token.unit = consumeAName();
-				return token;
-			} else if (next() == 0x25) {
-				consume();
-				const token = new Token(PERCENTAGE_TOKEN_TYPE, num.value);
-				token.repr = num.repr;
-				return token;
-			} else {
-				const token = new Token(NUMBER_TOKEN_TYPE, num.value);
-				token.type = "integer";
-				token.repr = num.repr;
-				token.type = num.type;
-				return token;
-			}
-		};
-
-		const consumeAnIdentlikeToken = function () {
-			const str = consumeAName();
-			if (str.toLowerCase() == "url" && next() == 0x28) {
-				consume();
-				while (whitespace(next(1)) && whitespace(next(2))) consume();
-				if (next() == 0x22 || next() == 0x27) {
-					return new Token(FUNCTION_TOKEN_TYPE, str);
-				} else if (whitespace(next()) && (next(2) == 0x22 || next(2) == 0x27)) {
-					return new Token(FUNCTION_TOKEN_TYPE, str);
-				} else {
-					return consumeAURLToken();
-				}
-			} else if (next() == 0x28) {
-				consume();
-				return new Token(FUNCTION_TOKEN_TYPE, str);
-			} else {
-				return new Token(IDENT_TOKEN_TYPE, str);
-			}
-		};
-
-		const consumeAStringToken = function (endingCodePoint) {
-			if (endingCodePoint === undefined) endingCodePoint = code;
-			let string = "";
-			while (consume()) {
-				if (code == endingCodePoint || eof()) {
-					return new Token(STRING_TOKEN_TYPE, string);
-				} else if (newline(code)) {
-					parseerror();
-					reconsume();
-					return new Token(BAD_STRING_TOKEN_TYPE);
-				} else if (code == 0x5c) {
-					if (eof(next())) {
-						donothing();
-					} else if (newline(next())) {
-						consume();
-					} else {
-						string += stringFromCode(consumeEscape());
-					}
-				} else {
-					string += stringFromCode(code);
-				}
-			}
-		};
-
-		const consumeAURLToken = function () {
-			const token = new Token(URL_TOKEN_TYPE, "");
-			while (whitespace(next())) consume();
-			if (eof(next())) return token;
-			while (consume()) {
-				if (code == 0x29 || eof()) {
-					return token;
-				} else if (whitespace(code)) {
-					while (whitespace(next())) consume();
-					if (next() == 0x29 || eof(next())) {
-						consume();
-						return token;
-					} else {
-						consumeTheRemnantsOfABadURL();
-						return new Token(BAD_URL_TOKEN_TYPE);
-					}
-				} else if (code == 0x22 || code == 0x27 || code == 0x28 || nonprintable(code)) {
-					parseerror();
-					consumeTheRemnantsOfABadURL();
-					return new Token(BAD_URL_TOKEN_TYPE);
-				} else if (code == 0x5c) {
-					if (startsWithAValidEscape()) {
-						token.value += stringFromCode(consumeEscape());
-					} else {
-						parseerror();
-						consumeTheRemnantsOfABadURL();
-						return new Token(BAD_URL_TOKEN_TYPE);
-					}
-				} else {
-					token.value += stringFromCode(code);
-				}
-			}
-		};
-
-		const consumeEscape = function () {
-			// Assume the the current character is the \
-			// and the next code point is not a newline.
-			consume();
-			if (hexdigit(code)) {
-				// Consume 1-6 hex digits
-				const digits = [code];
-				for (let total = 0; total < 5; total++) {
-					if (hexdigit(next())) {
-						consume();
-						digits.push(code);
-					} else {
-						break;
-					}
-				}
-				if (whitespace(next())) consume();
-				let value = parseInt(digits.map(function (x) { return String.fromCharCode(x); }).join(""), 16);
-				if (value > maximumallowedcodepoint) value = 0xfffd;
-				return value;
-			} else if (eof()) {
-				return 0xfffd;
-			} else {
-				return code;
-			}
-		};
-
-		const areAValidEscape = function (c1, c2) {
-			if (c1 != 0x5c) return false;
-			if (newline(c2)) return false;
-			return true;
-		};
-		const startsWithAValidEscape = function () {
-			return areAValidEscape(code, next());
-		};
-
-		const wouldStartAnIdentifier = function (c1, c2, c3) {
-			if (c1 == 0x2d) {
-				return namestartchar(c2) || c2 == 0x2d || areAValidEscape(c2, c3);
-			} else if (namestartchar(c1)) {
-				return true;
-			} else if (c1 == 0x5c) {
-				return areAValidEscape(c1, c2);
-			} else {
-				return false;
-			}
-		};
-		const startsWithAnIdentifier = function () {
-			return wouldStartAnIdentifier(code, next(1), next(2));
-		};
-
-		const wouldStartANumber = function (c1, c2, c3) {
-			if (c1 == 0x2b || c1 == 0x2d) {
-				if (digit(c2)) return true;
-				if (c2 == 0x2e && digit(c3)) return true;
-				return false;
-			} else if (c1 == 0x2e) {
-				if (digit(c2)) return true;
-				return false;
-			} else if (digit(c1)) {
-				return true;
-			} else {
-				return false;
-			}
-		};
-		const startsWithANumber = function () {
-			return wouldStartANumber(code, next(1), next(2));
-		};
-
-		const consumeAName = function () {
-			let result = "";
-			while (consume()) {
-				if (namechar(code)) {
-					result += stringFromCode(code);
-				} else if (startsWithAValidEscape()) {
-					result += stringFromCode(consumeEscape());
-				} else {
-					reconsume();
-					return result;
-				}
-			}
-		};
-
-		const consumeANumber = function () {
-			let repr = [];
-			let type = "integer";
-			if (next() == 0x2b || next() == 0x2d) {
-				consume();
-				repr += stringFromCode(code);
-			}
-			while (digit(next())) {
-				consume();
-				repr += stringFromCode(code);
-			}
-			if (next(1) == 0x2e && digit(next(2))) {
-				consume();
-				repr += stringFromCode(code);
-				consume();
-				repr += stringFromCode(code);
-				type = "number";
-				while (digit(next())) {
-					consume();
-					repr += stringFromCode(code);
-				}
-			}
-			const c1 = next(1), c2 = next(2), c3 = next(3);
-			if ((c1 == 0x45 || c1 == 0x65) && digit(c2)) {
-				consume();
-				repr += stringFromCode(code);
-				consume();
-				repr += stringFromCode(code);
-				type = "number";
-				while (digit(next())) {
-					consume();
-					repr += stringFromCode(code);
-				}
-			} else if ((c1 == 0x45 || c1 == 0x65) && (c2 == 0x2b || c2 == 0x2d) && digit(c3)) {
-				consume();
-				repr += stringFromCode(code);
-				consume();
-				repr += stringFromCode(code);
-				consume();
-				repr += stringFromCode(code);
-				type = "number";
-				while (digit(next())) {
-					consume();
-					repr += stringFromCode(code);
-				}
-			}
-			const value = convertAStringToANumber(repr);
-			return { type: type, value: value, repr: repr };
-		};
-
-		const convertAStringToANumber = function (string) {
-			// CSS's number rules are identical to JS, afaik.
-			return Number(string);
-		};
-
-		const consumeTheRemnantsOfABadURL = function () {
-			while (consume()) {
-				if (code == 0x29 || eof()) {
-					return;
-				} else if (startsWithAValidEscape()) {
-					consumeEscape();
-					donothing();
-				} else {
-					donothing();
-				}
-			}
-		};
-
-
-
 		let iterationCount = 0;
 		while (!eof(next())) {
-			tokens.push(consumeAToken());
+			tokens.push(consumeAToken(consume, next, eof, reconsume, parseerror, donothing));
 			iterationCount++;
 			if (iterationCount > str.length * 2) return "I'm infinite-looping!";
 		}