Skip to content

Commit

Permalink
fix(parser): fixed bunch of edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jul 25, 2019
1 parent e1da2d2 commit f18f5b4
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 87 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "meriyah",
"version": "1.4.2",
"version": "1.4.4",
"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
76 changes: 43 additions & 33 deletions src/common.ts
Expand Up @@ -36,7 +36,7 @@ export const enum Context {
AllowNewTarget = 1 << 26,
DisallowIn = 1 << 27,
OptionsIdentifierPattern = 1 << 28,
OptionsSpecDeviation = 1 << 29,
OptionsSpecDeviation = 1 << 29
}

export const enum PropertyKind {
Expand All @@ -60,15 +60,15 @@ export const enum PropertyKind {
export const enum BindingKind {
None = 0,
ArgumentList = 1 << 0,
EmptyBinding = 1 << 1,
EmptyBinding = 1 << 1,
Variable = 1 << 2,
Let = 1 << 3,
Const = 1 << 4,
Class = 1 << 5,
FunctionLexical = 1 << 6,
FunctionStatement = 1 << 7,
CatchPattern = 1 << 8,
CatchIdentifier = 1 << 9,
CatchIdentifier = 1 << 9,
CatchIdentifierOrPattern = CatchIdentifier | CatchPattern,
LexicalOrFunction = Variable | FunctionLexical,
LexicalBinding = Let | Const | FunctionLexical | FunctionStatement | Class
Expand All @@ -83,7 +83,7 @@ export const enum BindingOrigin {
Export = 1 << 4,
Other = 1 << 5,
BlockStatement = 1 << 7,
TopLevel = 1 << 8,
TopLevel = 1 << 8
}

export const enum AssignmentKind {
Expand Down Expand Up @@ -114,7 +114,7 @@ export const enum Flags {
Octals = 1 << 6,
SimpleParameterList = 1 << 7,
HasStrictReserved = 1 << 8,
StrictEvalArguments = 1 << 9,
StrictEvalArguments = 1 << 9
}

export const enum HoistedClassFlags {
Expand Down Expand Up @@ -216,8 +216,11 @@ export interface ParserState {
*/

export function matchOrInsertSemicolon(parser: ParserState, context: Context, specDeviation?: number): void {
if ((parser.flags & Flags.NewLine) === 0 && (parser.token & Token.IsAutoSemicolon) !== Token.IsAutoSemicolon
&& !specDeviation) {
if (
(parser.flags & Flags.NewLine) === 0 &&
(parser.token & Token.IsAutoSemicolon) !== Token.IsAutoSemicolon &&
!specDeviation
) {
report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
}
consumeOpt(parser, context, Token.Semicolon);
Expand Down Expand Up @@ -353,9 +356,9 @@ export function validateBindingIdentifier(
report(parser, Errors.KeywordNotId);
}

// The BoundNames of LexicalDeclaration and ForDeclaration must not
// contain 'let'. (CatchParameter is the only lexical binding form
// without this restriction.)
// The BoundNames of LexicalDeclaration and ForDeclaration must not
// contain 'let'. (CatchParameter is the only lexical binding form
// without this restriction.)
if (type & (BindingKind.Let | BindingKind.Const) && t === Token.LetKeyword) {
report(parser, Errors.InvalidLetConstBinding);
}
Expand Down Expand Up @@ -503,8 +506,10 @@ export function recordScopeError(parser: ParserState, type: Errors): ScopeError
const { index, line, column } = parser;
return {
type,
index, line, column
}
index,
line,
column
};
}

/**
Expand All @@ -531,7 +536,6 @@ export function addChildScope(parent: any, type: ScopeKind): ScopeState {
};
}


/**
* Adds either a var binding or a block scoped binding.
*
Expand All @@ -542,21 +546,23 @@ export function addChildScope(parent: any, type: ScopeKind): ScopeState {
* @param type Binding kind
* @param origin Binding Origin
*/
export function addVarOrBlock(parser: ParserState,
export function addVarOrBlock(
parser: ParserState,
context: Context,
scope: ScopeState,
name: string,
type: BindingKind,
origin: BindingOrigin) {
if (type & BindingKind.Variable) {
addVarName(parser, context, scope, name, type);
} else {
addBlockName(parser, context, scope, name, type, BindingOrigin.Other);
}
if (origin & BindingOrigin.Export) {
updateExportsList(parser, parser.tokenValue);
addBindingToExports(parser, parser.tokenValue);
}
origin: BindingOrigin
) {
if (type & BindingKind.Variable) {
addVarName(parser, context, scope, name, type);
} else {
addBlockName(parser, context, scope, name, type, BindingOrigin.Other);
}
if (origin & BindingOrigin.Export) {
updateExportsList(parser, parser.tokenValue);
addBindingToExports(parser, parser.tokenValue);
}
}

/**
Expand All @@ -575,15 +581,15 @@ export function addVarName(
name: string,
type: BindingKind
): void {

let currentScope: any = scope;

while (currentScope && (currentScope.type & ScopeKind.FuncRoot) === 0) {

const value: ScopeKind = currentScope['#' + name];

if (value & BindingKind.LexicalBinding) {
if (context & Context.OptionsWebCompat && (context & Context.Strict) === 0 &&
if (
context & Context.OptionsWebCompat &&
(context & Context.Strict) === 0 &&
((type & BindingKind.FunctionStatement && value & BindingKind.LexicalOrFunction) ||
(value & BindingKind.FunctionStatement && type & BindingKind.LexicalOrFunction))
) {
Expand All @@ -592,12 +598,16 @@ export function addVarName(
}
}
if (currentScope === scope) {
if (value & BindingKind.ArgumentList && type & BindingKind.ArgumentList) {
currentScope.scopeError = recordScopeError(parser, Errors.Unexpected);
}
if (value & BindingKind.ArgumentList && type & BindingKind.ArgumentList) {
currentScope.scopeError = recordScopeError(parser, Errors.Unexpected);
}
}
if (value & (BindingKind.CatchIdentifier | BindingKind.CatchPattern)) {
if (((value & BindingKind.CatchIdentifier) === 0 || (context & Context.OptionsWebCompat) === 0) || context & Context.Strict) {
if (
(value & BindingKind.CatchIdentifier) === 0 ||
(context & Context.OptionsWebCompat) === 0 ||
context & Context.Strict
) {
report(parser, Errors.DuplicateBinding, name);
}
}
Expand Down Expand Up @@ -626,7 +636,6 @@ export function addBlockName(
type: BindingKind,
origin: BindingOrigin
) {

const value = (scope as any)['#' + name];

if (value && (value & BindingKind.EmptyBinding) === 0) {
Expand Down Expand Up @@ -656,7 +665,8 @@ export function addBlockName(
}

if (scope.type & ScopeKind.CatchBody) {
if ((scope as any).parent['#' + name] & BindingKind.CatchIdentifierOrPattern) report(parser, Errors.ShadowedCatchClause, name);
if ((scope as any).parent['#' + name] & BindingKind.CatchIdentifierOrPattern)
report(parser, Errors.ShadowedCatchClause, name);
}

(scope as any)['#' + name] = type;
Expand Down
3 changes: 2 additions & 1 deletion src/errors.ts
Expand Up @@ -217,7 +217,8 @@ export const errorMessages: {
[Errors.AccessorWrongArgs]: '%0 functions must have exactly %1 argument%2',
[Errors.BadSetterRestParameter]: 'Setter function argument must not be a rest parameter',
[Errors.DeclNoName]: '%0 declaration must have a name in this context',
[Errors.StrictFunctionName]: 'Function name may not be eval or arguments in strict mode',
[Errors.StrictFunctionName]:
'Function name may not contain any reserved words or be eval or arguments in strict mode',
[Errors.RestMissingArg]: 'The rest operator is missing an argument',
[Errors.CantAssignToInit]: 'Cannot assign to lhs, not destructible with this initializer',
[Errors.InvalidGeneratorGetter]: 'A getter cannot be a generator',
Expand Down
4 changes: 1 addition & 3 deletions src/lexer/common.ts
Expand Up @@ -6,9 +6,7 @@ import { report, Errors } from '../errors';
export const enum LexerState {
None = 0,
NewLine = 1 << 0,
SameLine = 1 << 1,
LastIsCR = 1 << 2,
InJSXMode = 1 << 3
LastIsCR = 1 << 2
}

export const enum NumberKind {
Expand Down
2 changes: 1 addition & 1 deletion src/meriyah.ts
Expand Up @@ -27,4 +27,4 @@ export function parse(source: string, options?: Options): ESTree.Program {
export { ESTree, Options };

// Export current version
export const version = '1.4.2';
export const version = '1.4.4';
76 changes: 28 additions & 48 deletions src/parser.ts
Expand Up @@ -1090,6 +1090,8 @@ export function parseAsyncArrowOrAsyncFunctionDeclaration(
(context | Context.DisallowIn) ^ Context.DisallowIn,
expr,
1,
BindingKind.ArgumentList,
BindingOrigin.None,
asyncNewLine,
start,
line,
Expand Down Expand Up @@ -1900,6 +1902,8 @@ export function parseLetIdentOrVarDeclarationStatement(

if (context & Context.Strict) report(parser, Errors.UnexpectedLetStrictReserved);

if (parser.token === Token.LetKeyword) report(parser, Errors.InvalidLetBoundName);

/** LabelledStatement[Yield, Await, Return]:
*
* ExpressionStatement | LabelledStatement ::
Expand Down Expand Up @@ -2086,7 +2090,7 @@ export function parseVariableDeclarationList(
*
* @param parser Parser object
* @param context Context masks
* * @param start Start pos of node
* @param start Start pos of node
* @param start Start pos of node
* @param line
* @param column
Expand Down Expand Up @@ -2158,10 +2162,9 @@ function parseVariableDeclaration(
*
* @param parser Parser object
* @param context Context masks
* @param start Start pos of node
* @param start Start pos of node
* @param line
* @param column
* @param start Start pos of node
* @param line
* @param column
*/
export function parseForStatement(
Expand Down Expand Up @@ -2329,9 +2332,7 @@ export function parseForStatement(
});
}

if (forAwait) {
report(parser, Errors.InvalidForAwait);
}
if (forAwait) report(parser, Errors.InvalidForAwait);

if (!isVarDecl) {
if (destructible & DestructuringKind.MustDestruct && parser.token !== Token.Assign) {
Expand Down Expand Up @@ -2732,6 +2733,8 @@ function parseExportDeclaration(
(context | Context.DisallowIn) ^ Context.DisallowIn,
declaration,
1,
BindingKind.ArgumentList,
BindingOrigin.None,
flags,
idxBeforeAsync,
lineBeforeAsync,
Expand Down Expand Up @@ -7179,6 +7182,8 @@ export function parseAsyncExpression(
(context | Context.DisallowIn) ^ Context.DisallowIn,
expr,
assignable,
BindingKind.ArgumentList,
BindingOrigin.None,
flags,
start,
line,
Expand Down Expand Up @@ -7210,13 +7215,21 @@ export function parseAsyncExpression(
* @param context Context masks
* @param callee ESTree AST node
* @param assignable
* @param asyncNewLine
* @param kind Binding kind
* @param origin Binding origin
* @param flags Mutual parser flags
* @param start Start pos of node
* @param line Line pos of node
* @param column Column pos of node
*/

export function parseAsyncArrowOrCallExpression(
parser: ParserState,
context: Context,
callee: ESTree.Identifier | void,
assignable: 0 | 1,
kind: BindingKind,
origin: BindingOrigin,
flags: Flags,
start: number,
line: number,
Expand Down Expand Up @@ -7253,20 +7266,9 @@ export function parseAsyncArrowOrCallExpression(

if (token & (Token.IsIdentifier | Token.Keyword)) {
if (scope) {
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, BindingOrigin.Other);
addBlockName(parser, context, scope, parser.tokenValue, kind, BindingOrigin.Other);
}
expr = parsePrimaryExpressionExtended(
parser,
context,
BindingKind.ArgumentList,
0,
1,
0,
1,
tokenPos,
linePos,
colPos
);
expr = parsePrimaryExpressionExtended(parser, context, kind, 0, 1, 0, 1, tokenPos, linePos, colPos);

if ((parser.token & Token.IsCommaOrRightParen) === Token.IsCommaOrRightParen) {
if (parser.assignable & AssignmentKind.NotAssignable) {
Expand Down Expand Up @@ -7296,30 +7298,8 @@ export function parseAsyncArrowOrCallExpression(
} else if (token & Token.IsPatternStart) {
expr =
token === Token.LeftBrace
? parseObjectLiteralOrPattern(
parser,
context,
scope,
0,
1,
BindingKind.ArgumentList,
BindingOrigin.None,
tokenPos,
linePos,
colPos
)
: parseArrayExpressionOrPattern(
parser,
context,
scope,
0,
1,
BindingKind.ArgumentList,
BindingOrigin.None,
tokenPos,
linePos,
colPos
);
? parseObjectLiteralOrPattern(parser, context, scope, 0, 1, kind, origin, tokenPos, linePos, colPos)
: parseArrayExpressionOrPattern(parser, context, scope, 0, 1, kind, origin, tokenPos, linePos, colPos);

destructible |= parser.destructible;

Expand All @@ -7344,8 +7324,8 @@ export function parseAsyncArrowOrCallExpression(
context,
scope,
Token.RightParen,
BindingKind.ArgumentList,
BindingOrigin.None,
kind,
origin,
1,
1,
tokenPos,
Expand Down
4 changes: 4 additions & 0 deletions test/parser/declarations/let.ts
Expand Up @@ -486,6 +486,10 @@ describe('Declarations - Let', () => {
['let [...[ x ] = []] = [];', Context.None],
['let [...[ x ] = []] = [];', Context.None],
['let [...{ x } = []] = [];', Context.None],
['let\\nlet', Context.None],
['do let [x] = 0; while (false);', Context.None],
['if (x) let [x] = y; else x;', Context.None],
['do let [] while (a);', Context.None],
['let [...x, y] = [1, 2, 3];', Context.None],
['let [...{ x }, y] = [1, 2, 3];', Context.None],
['let [...x = []] = [];', Context.None],
Expand Down

0 comments on commit f18f5b4

Please sign in to comment.