Skip to content

Commit

Permalink
fix(parser): fixed incorrect error locations
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jun 27, 2019
1 parent c6d24b6 commit 6d894e5
Show file tree
Hide file tree
Showing 14 changed files with 479 additions and 167 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "meriyah",
"version": "1.0.1",
"version": "1.0.2",
"description": "A 100% compliant, self-hosted javascript parser with high focus on both performance and stability",
"main": "dist/meriyah.umd.js",
"module": "dist/meriyah.esm.js",
Expand Down
4 changes: 2 additions & 2 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export const enum PropertyKind {

export const enum BindingType {
None = 0,
Variable = 1 << 0,
ArgList = 1 << 1,
ArgList = 1 << 0,
Variable = 1 << 2,
Let = 1 << 3,
Const = 1 << 4
}
Expand Down
9 changes: 4 additions & 5 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export const enum Errors {
ExpectedToken,
CantAssignTo,
CantAssignToAsyncArrow,
CantAssignToValidRHS,
SuperNoConstructor,
InvalidSuperProperty,
UnexpectedToken,
Expand Down Expand Up @@ -155,7 +154,8 @@ export const enum Errors {
DuplicateExportBinding,
UndeclaredExportedBinding,
UnexpectedPrivateField,
DuplicateLetConstBinding
DuplicateLetConstBinding,
CantAssignToValidRHS
}

/*@internal*/
Expand All @@ -173,6 +173,7 @@ export const errorMessages: {
[Errors.StrictOctalLiteral]: 'Octal literals are not allowed in strict mode',
[Errors.StrictDecimalWithLeadingZero]: 'Decimal integer literals with a leading zero are forbidden in strict mode',
[Errors.ExpectedNumberInRadix]: 'Expected number in radix %0',
[Errors.CantAssignToValidRHS]: 'Invalid left-hand side assignment to a destructible right-hand side',
[Errors.MissingExponent]: 'Non-number found after exponent indicator',
[Errors.InvalidBigInt]: 'Invalid BigIntLiteral',
[Errors.IDStartAfterNumber]: 'No identifiers allowed directly after numeric literal',
Expand All @@ -189,7 +190,6 @@ export const errorMessages: {
[Errors.ExpectedToken]: "Expected '%0'",
[Errors.CantAssignTo]: 'Invalid left-hand side in assignment',
[Errors.CantAssignToAsyncArrow]: 'Invalid left-hand side in async arrow',
[Errors.CantAssignToValidRHS]: 'Invalid left-hand side assignment to a destructible right-hand side',
[Errors.SuperNoConstructor]:
'Calls to super must be in the "constructor" method of a class expression or class declaration that has a superclass',
[Errors.InvalidSuperProperty]: 'Member access on super must be in a method',
Expand Down Expand Up @@ -331,10 +331,9 @@ export class ParseError extends SyntaxError {
public column: number;
public description: string;
constructor(startindex: number, line: number, column: number, type: Errors, ...params: string[]) {
let message =
const message =
'[' + line + ':' + column + ']: ' + errorMessages[type].replace(/%(\d+)/g, (_: string, i: number) => params[i]);
super(`${message}`);

this.index = startindex;
this.line = line;
this.column = column;
Expand Down
4 changes: 0 additions & 4 deletions src/lexer/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ export function consumeMultiUnitCodePoint(parser: ParserState, hi: number): bool
return true;
}

export function storeRaw(parser: ParserState, start: number) {
parser.tokenRaw = parser.source.slice(start, parser.index);
}

/**
* Use to consume a line feed instead of `advanceNewline`.
*/
Expand Down
3 changes: 1 addition & 2 deletions src/lexer/identifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function scanIdentifier(parser: ParserState, context: Context): Token {
while ((CharTypes[nextCP(parser)] & CharFlags.IdentifierPart) !== 0) {}
parser.tokenValue = parser.source.slice(parser.tokenIndex, parser.index);
const hasEscape = CharTypes[parser.nextCP] & CharFlags.BackSlash;
if ((parser.nextCP & ~0x7f) === 0 && !hasEscape) {
if (!hasEscape && parser.nextCP < 0x7e) {
return descKeywordTable[parser.tokenValue] || Token.Identifier;
}

Expand Down Expand Up @@ -132,7 +132,6 @@ export function scanIdentifierUnicodeEscape(parser: ParserState): number | void
*/
export function scanUnicodeEscapeValue(parser: ParserState): number {
let codePoint = 0;

// First handle a delimited Unicode escape, e.g. \u{1F4A9}
if (parser.nextCP === Chars.LeftBrace) {
const startPos = parser.index;
Expand Down
1 change: 0 additions & 1 deletion src/lexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export {
isExoticECMAScriptWhitespace,
fromCodePoint,
toHex,
storeRaw,
consumeLineFeed,
advanceNewline,
LexerState
Expand Down
34 changes: 15 additions & 19 deletions src/lexer/numeric.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ParserState, Context, Flags } from '../common';
import { Token } from '../token';
import { nextCP, toHex, CharTypes, CharFlags, isIdentifierStart, storeRaw } from './';
import { nextCP, toHex, CharTypes, CharFlags, isIdentifierStart } from './';
import { Chars } from '../chars';
import { report, Errors } from '../errors';

Expand Down Expand Up @@ -136,24 +136,20 @@ export function scanNumber(parser: ParserState, context: Context, isFloat: 0 | 1

// The source character immediately following a numeric literal must
// not be an identifier start or a decimal digit
if ((parser.index < parser.end && CharTypes[parser.nextCP] & CharFlags.Decimal) || isIdentifierStart(parser.nextCP)) {
if (CharTypes[parser.nextCP] & CharFlags.Decimal || isIdentifierStart(parser.nextCP)) {
report(parser, Errors.IDStartAfterNumber);
}

if (kind & (NumberKind.ImplicitOctal | NumberKind.Binary | NumberKind.Hex | NumberKind.Octal)) {
parser.tokenValue = value;
} else {
const raw = parser.source.slice(parser.tokenIndex, parser.index);
parser.tokenValue =
kind & NumberKind.DecimalWithLeadingZero ? parseFloat(raw) : isBigInt ? parseInt(raw, 0xa) : +raw;
}

if (isBigInt) {
storeRaw(parser, parser.tokenIndex);
return Token.BigIntLiteral;
}

if (context & Context.OptionsRaw) storeRaw(parser, parser.tokenIndex);

return Token.NumericLiteral;
if (context & Context.OptionsRaw) parser.tokenRaw = parser.source.slice(parser.tokenIndex, parser.index);
parser.tokenValue =
kind & (NumberKind.ImplicitOctal | NumberKind.Binary | NumberKind.Hex | NumberKind.Octal)
? value
: kind & NumberKind.DecimalWithLeadingZero
? parseFloat(parser.source.slice(parser.tokenIndex, parser.index))
: isBigInt
? parseInt(parser.source.slice(parser.tokenIndex, parser.index), 0xa)
: +parser.source.slice(parser.tokenIndex, parser.index);

if (context & Context.OptionsRaw || isBigInt) parser.tokenRaw = parser.source.slice(parser.tokenIndex, parser.index);

return isBigInt ? Token.BigIntLiteral : Token.NumericLiteral;
}
57 changes: 29 additions & 28 deletions src/lexer/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
nextCP(parser);
return token;

// Skip over non-EOL whitespace chars
// Skip over non-EOL whitespace chars.
case Token.WhiteSpace:
nextCP(parser);
break;
Expand All @@ -234,14 +234,13 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
case Token.NumericLiteral:
return scanNumber(parser, context, /* isFloat */ 0);

// Look for a string or a template string.
// Look for a string or a template string
case Token.StringLiteral:
return scanString(parser, context);

case Token.Template:
return scanTemplate(parser, context);

// Escaped identifiers
case Token.EscapedIdentifier:
return scanUnicodeIdentifier(parser, context);

Expand All @@ -266,27 +265,6 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
nextCP(parser);
return Token.ModuloAssign;

// `=`, `==`, `===`, `=>`
case Token.Assign: {
nextCP(parser);
if (parser.index >= parser.end) return Token.Assign;
const next = parser.nextCP;

if (next === Chars.EqualSign) {
if (nextCP(parser) === Chars.EqualSign) {
nextCP(parser);
return Token.StrictEqual;
} else {
return Token.LooseEqual;
}
} else if (next === Chars.GreaterThan) {
nextCP(parser);
return Token.Arrow;
}

return Token.Assign;
}

// `*`, `**`, `*=`, `**=`
case Token.Multiply: {
nextCP(parser);
Expand Down Expand Up @@ -388,7 +366,8 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le

switch (parser.nextCP) {
case Chars.LessThan:
if (nextCP(parser) === Chars.EqualSign) {
nextCP(parser);
if ((parser.nextCP as number) === Chars.EqualSign) {
nextCP(parser);
return Token.ShiftLeftAssign;
} else {
Expand All @@ -400,6 +379,7 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
return Token.LessThanOrEqual;

case Chars.Exclamation:
// Treat HTML begin-comment as comment-till-end-of-line.
if (
(context & Context.Module) === 0 &&
parser.source.charCodeAt(parser.index + 1) === Chars.Hyphen &&
Expand All @@ -414,6 +394,28 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
return Token.LessThan;
}

// `=`, `==`, `===`, `=>`
case Token.Assign: {
nextCP(parser);
if (parser.index >= parser.end) return Token.Assign;
const next = parser.nextCP;

if (next === Chars.EqualSign) {
nextCP(parser);
if (parser.nextCP === Chars.EqualSign) {
nextCP(parser);
return Token.StrictEqual;
} else {
return Token.LooseEqual;
}
} else if (next === Chars.GreaterThan) {
nextCP(parser);
return Token.Arrow;
}

return Token.Assign;
}

// `|`, `||`, `|=`
case Token.BitwiseOr: {
nextCP(parser);
Expand Down Expand Up @@ -449,7 +451,8 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
const next = parser.nextCP;

if (next === Chars.GreaterThan) {
if (nextCP(parser) === Chars.EqualSign) {
nextCP(parser);
if (parser.nextCP === Chars.EqualSign) {
nextCP(parser);
return Token.LogicalShiftRightAssign;
} else {
Expand Down Expand Up @@ -498,8 +501,6 @@ export function scanSingleToken(parser: ParserState, context: Context, state: Le
// unreachable
}
} else {
// Non-ASCII code points can only be identifiers or whitespace.

if ((first ^ Chars.LineSeparator) <= 1) {
state = (state | LexerState.LastIsCR | LexerState.NewLine) ^ LexerState.LastIsCR;
advanceNewline(parser);
Expand Down
4 changes: 2 additions & 2 deletions src/lexer/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ParserState, Context, Flags } from '../common';
import { Token } from '../token';
import { Chars } from '../chars';
import { report, Errors } from '../errors';
import { toHex, nextCP, fromCodePoint, CharTypes, CharFlags, storeRaw } from './';
import { toHex, nextCP, fromCodePoint, CharTypes, CharFlags } from './';

// Intentionally negative
export const enum Escape {
Expand All @@ -26,7 +26,7 @@ export function scanString(parser: ParserState, context: Context): any {
if (ch === quote) {
ret += parser.source.slice(marker, parser.index);
nextCP(parser); // skip closing quote
if (context & Context.OptionsRaw) storeRaw(parser, start);
if (context & Context.OptionsRaw) parser.tokenRaw = parser.source.slice(start, parser.index);
parser.tokenValue = ret;
return Token.StringLiteral;
}
Expand Down

0 comments on commit 6d894e5

Please sign in to comment.