buntis
Version:
A 100% compliant, self-hosted typescript parser that emits an ESTree-compatible abstract syntax tree
107 lines (96 loc) • 3.29 kB
text/typescript
import { CharFlags, CharTypes } from './charClassifier';
import { Chars } from '../chars';
import { Token } from '../token';
import { ParserState, Context } from '../common';
import { report, Errors } from '../errors';
import { advance } from './common';
import { scanSingleToken, firstCharKinds } from './scan';
/**
* Scans JSX attribute value
*
* @param parser The parser instance
* @param context Context masks
*/
export function scanJSXAttributeValue(parser: ParserState, context: Context): Token {
parser.startPos = parser.index;
parser.startColumn = parser.column;
parser.startLine = parser.line;
if (parser.nextCodePoint === Chars.SingleQuote || parser.nextCodePoint === Chars.DoubleQuote) {
parser.token = scanJSXString(parser, context);
} else {
parser.token = scanSingleToken(parser, context);
}
return parser.token;
}
/**
* Scans JSX string
*
* @param parser The parser object
*/
export function scanJSXString(parser: ParserState, context: Context): Token {
const quote = parser.nextCodePoint;
let char = advance(parser);
const start = parser.index;
while (char !== quote) {
if (parser.index >= parser.length) report(parser, context, Errors.UnterminatedString, /* early */ 0);
char = advance(parser);
}
// check for unterminated string
if (char !== quote) report(parser, context, Errors.UnterminatedString, /* early */ 0);
parser.tokenValue = parser.source.slice(start, parser.index);
advance(parser); // skip the quote
return Token.StringLiteral;
}
/**
* Scans JSX token
*
* @param parser The parser object
*/
export function scanJSXToken(parser: ParserState): Token {
parser.startPos = parser.tokenPos = parser.index;
parser.startColumn = parser.endColumn = parser.column;
parser.startLine = parser.endLine = parser.line;
if (parser.index >= parser.length) return (parser.token = Token.EndOfSource);
const token = firstCharKinds[parser.source.charCodeAt(parser.index)];
switch (token) {
// '<'
case Token.LessThan: {
advance(parser);
if (parser.nextCodePoint === Chars.Slash) {
advance(parser);
parser.token = Token.JSXClose;
} else {
parser.token = Token.LessThan;
}
break;
}
// '{'
case Token.LeftBrace: {
advance(parser);
parser.token = Token.LeftBrace;
break;
}
default:
while (parser.index < parser.length && (CharTypes[advance(parser)] & CharFlags.JSXToken) === 0) {}
parser.tokenValue = parser.source.slice(parser.tokenPos, parser.index);
parser.token = Token.JSXText;
}
return parser.token;
}
/**
* Scans JSX identifier
*
* @param parser The parser instance
*/
export function scanJSXIdentifier(parser: ParserState): Token {
if ((parser.token & (Token.Keywords | Token.Contextual | Token.FutureReserved | Token.IsIdentifier)) !== 0) {
const { index } = parser;
let char = parser.nextCodePoint;
while (CharTypes[char] & (CharFlags.Hyphen | CharFlags.IdentifierPart)) {
char = advance(parser);
}
parser.tokenValue += parser.source.slice(index, parser.index);
}
parser.token = Token.Identifier;
return parser.token;
}