Skip to content

Commit

Permalink
fix(parser): tweaked and optimized JSX lexer code
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jul 5, 2019
1 parent 12ba7e6 commit a701555
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 48 deletions.
10 changes: 6 additions & 4 deletions src/lexer/charClassifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const enum CharFlags {
CarriageReturn = 1 << 19,
LineFeed = 1 << 20,
Underscore = 1 << 21,
StringLiteral = 1 << 22,
JSXToken = 1 << 23,
}

/**
Expand Down Expand Up @@ -57,12 +59,12 @@ export const CharTypes = [
CharFlags.None /* 0x1F */,
CharFlags.None /* 0x20 */,
CharFlags.None /* 0x21 ! */,
CharFlags.None /* 0x22 */,
CharFlags.StringLiteral /* 0x22 */,
CharFlags.None /* 0x23 # */,
CharFlags.IdentifierStart | CharFlags.IdentifierPart /* 0x24 $ */,
CharFlags.None /* 0x25 % */,
CharFlags.None /* 0x26 & */,
CharFlags.None /* 0x27 */,
CharFlags.StringLiteral /* 0x27 */,
CharFlags.None /* 0x28 */,
CharFlags.None /* 0x29 */,
CharFlags.None /* 0x2A */,
Expand All @@ -83,7 +85,7 @@ export const CharTypes = [
CharFlags.IdentifierPart | CharFlags.Decimal | CharFlags.ImplicitOctalDigits | CharFlags.Hex /* 0x39 9 */,
CharFlags.None /* 0x3A */,
CharFlags.None /* 0x3B */,
CharFlags.None /* 0x3C < */,
CharFlags.JSXToken /* 0x3C < */,
CharFlags.None /* 0x3D = */,
CharFlags.None /* 0x3E > */,
CharFlags.None /* 0x3F */,
Expand Down Expand Up @@ -146,7 +148,7 @@ export const CharTypes = [
CharFlags.IdentifierStart | CharFlags.IdentifierPart | CharFlags.KeywordCandidate /* 0x78 x */,
CharFlags.IdentifierStart | CharFlags.IdentifierPart | CharFlags.KeywordCandidate /* 0x79 y */,
CharFlags.IdentifierStart | CharFlags.IdentifierPart | CharFlags.KeywordCandidate /* 0x7A z */,
CharFlags.None /* 0x7B */,
CharFlags.JSXToken /* 0x7B */,
CharFlags.None /* 0x7C */,
CharFlags.None /* 0x7D */,
CharFlags.None /* 0x7E */,
Expand Down
84 changes: 44 additions & 40 deletions src/lexer/jsx.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import { isIdentifierStart, isIdentifierPart } from './charClassifier';
import { CharFlags, CharTypes, isIdentifierStart, isIdentifierPart } from './charClassifier';
import { Chars } from '../chars';
import { Token } from '../token';
import { ParserState, Context } from '../common';
import { report, Errors } from '../errors';
import { nextCP, nextToken } from './';
import { nextCP, LexerState } from './';
import { scanSingleToken } from './scan';

/**
* Scans JSX attribute value
*
* @param parser The parser instance
* @param context Context masks
*/
export function scanJSXAttributeValue(parser: ParserState, context: Context): Token {
parser.startIndex = parser.index;
parser.token =
CharTypes[parser.nextCP] & CharFlags.StringLiteral
? scanJSXString(parser)
: scanSingleToken(parser, context, LexerState.None);
return parser.token;
}

/**
* Scans JSX string
*
* @param parser The parser object
*/
export function scanJSXString(parser: ParserState): Token {
const quote = parser.nextCP;
let char = nextCP(parser);
Expand All @@ -21,75 +42,58 @@ export function scanJSXString(parser: ParserState): Token {
return Token.StringLiteral;
}

/**
* Scans JSX token
*
* @param parser The parser object
*/
export function scanJSXToken(parser: ParserState): Token {
parser.startIndex = parser.tokenIndex = parser.index;

if (parser.index >= parser.end) {
return (parser.token = Token.EOF);
}
if (parser.index >= parser.end) return (parser.token = Token.EOF);

let char = parser.source.charCodeAt(parser.index);

if (char === Chars.LessThan) {
if (parser.source.charCodeAt(parser.index + 1) === Chars.Slash) {
parser.index += 2;
parser.nextCP = parser.source.charCodeAt(parser.index);
parser.column += 2;
parser.nextCP = parser.source.charCodeAt((parser.index += 2));
return (parser.token = Token.JSXClose);
}
++parser.index;
parser.nextCP = parser.source.charCodeAt(parser.index);
nextCP(parser);
return (parser.token = Token.LessThan);
}

if (char === Chars.LeftBrace) {
++parser.index;
parser.nextCP = parser.source.charCodeAt(parser.index);
nextCP(parser);
return (parser.token = Token.LeftBrace);
}

while (parser.index < parser.end) {
parser.index++;
char = parser.source.charCodeAt(parser.index);
if (char === Chars.LeftBrace || char === Chars.LessThan) {
break;
}
if (CharTypes[nextCP(parser)] & CharFlags.JSXToken) break;
}
parser.nextCP = parser.source.charCodeAt(parser.index);

parser.tokenValue = parser.source.slice(parser.tokenIndex, parser.index);
return (parser.token = Token.JSXText);
}

/**
* Scans JSX identifier
* @param parser The parser instance
* @param context Context masks
*/
export function scanJSXIdentifier(parser: ParserState): Token {
if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
const firstCharPosition = parser.index;
const { index } = parser;

while (parser.index < parser.end) {
const char = parser.nextCP;
if (
char === Chars.Hyphen ||
(firstCharPosition === parser.index ? isIdentifierStart(char) : isIdentifierPart(char))
) {
parser.index++;
if (char === Chars.Hyphen || (index === parser.index ? isIdentifierStart(char) : isIdentifierPart(char))) {
nextCP(parser);
} else break;
parser.nextCP = parser.source.charCodeAt(parser.index);
}

parser.tokenValue += parser.source.slice(firstCharPosition, parser.index); // - firstCharPosition);
parser.tokenValue += parser.source.slice(index, parser.index);
}

return parser.token;
}

export function scanJsxAttributeValue(parser: ParserState, context: Context): any {
parser.startIndex = parser.index;

switch (parser.nextCP) {
case Chars.DoubleQuote:
case Chars.SingleQuote:
parser.token = scanJSXString(parser);
return (parser.token = Token.StringLiteral);
default:
// If this scans anything other than `{`, it's a parse error.
nextToken(parser, context);
}
}
6 changes: 2 additions & 4 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Token, KeywordDescTable } from './token';
import * as ESTree from './estree';
import { report, reportAt, Errors } from './errors';
import { scanTemplateTail } from './lexer/template';
import { scanJSXIdentifier, scanJSXToken, scanJsxAttributeValue } from './lexer/jsx';
import { scanJSXIdentifier, scanJSXToken, scanJSXAttributeValue } from './lexer/jsx';

import {
declareName,
Expand Down Expand Up @@ -8352,9 +8352,7 @@ function parseJsxAttribute(
}

if (parser.token === Token.Assign) {
scanJsxAttributeValue(parser, context);

switch (parser.token) {
switch (scanJSXAttributeValue(parser, context)) {
case Token.StringLiteral:
value = parseLiteral(parser, context, start, line, column);
break;
Expand Down

0 comments on commit a701555

Please sign in to comment.