Skip to content

Commit

Permalink
fix(parser): fixed possible conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jun 18, 2019
1 parent 4b7a9b5 commit b72ffe2
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 52 deletions.
10 changes: 5 additions & 5 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,12 @@ export function isPropertyWithPrivateFieldKey(expr: any): boolean {
export function isValidLabel(parser: ParserState, labels: any, name: string, isIterationStatement: 0 | 1): 0 | 1 {

while (labels) {
if (labels['' + name]) {
if (labels['$' + name]) {
if (isIterationStatement) report(parser, Errors.InvalidNestedStatement);
return 1;
}
if (isIterationStatement && labels.loop) isIterationStatement = 0;
labels = labels[''];
labels = labels['$'];
}

return 0;
Expand All @@ -354,11 +354,11 @@ export function isValidLabel(parser: ParserState, labels: any, name: string, isI
export function validateAndDeclareLabel(parser: ParserState, labels: any, name: string): void {
let set = labels;
do {
if (set['' + name]) report(parser, Errors.LabelRedeclaration, name);
set = set[''];
if (set['$' + name]) report(parser, Errors.LabelRedeclaration, name);
set = set['$'];
} while (set);

labels['' + name] = 1;
labels['$' + name] = 1;
}


Expand Down
22 changes: 11 additions & 11 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export function parseSource(source: string, options: Options | void, context: Co

if (context & Context.OptionsLexical) {
for (let key in parser.exportedBindings) {
if (key !== '#default' && (scope.var[key] === undefined && scope.lex[key] === undefined)) {
if (key !== '$default' && (scope.var[key] === undefined && scope.lexicals[key] === undefined)) {
report(parser, Errors.UndeclaredExportedBinding, key.slice(1));
}
}
Expand Down Expand Up @@ -667,7 +667,7 @@ export function parseBlock(
parser,
context & ~Context.TopLevel,
scope,
{ '€': labels },
{ $: labels },
parser.tokenIndex
) as any);
}
Expand Down Expand Up @@ -1090,7 +1090,7 @@ export function parseConsequentOrAlternate(
// Disallow if web compability is off
(context & Context.OptionsWebCompat) === 0 ||
parser.token !== Token.FunctionKeyword
? parseStatement(parser, context, scope, { '€': labels }, FunctionStatement.Disallow, parser.tokenIndex)
? parseStatement(parser, context, scope, { $: labels }, FunctionStatement.Disallow, parser.tokenIndex)
: parseFunctionDeclaration(parser, context, scope, 0, HoistedFunctionFlags.None, 0, start);
}

Expand Down Expand Up @@ -1144,7 +1144,7 @@ export function parseSwitchStatement(
(context | Context.InSwitch | Context.TopLevel) ^ Context.TopLevel,
scope,
{
'€': labels
$: labels
},
parser.tokenIndex
) as ESTree.Statement);
Expand Down Expand Up @@ -1215,7 +1215,7 @@ export function parseIterationStatementBody(
parser,
((context | Context.TopLevel | Context.DisallowIn) ^ (Context.TopLevel | Context.DisallowIn)) | Context.InIteration,
scope,
{ loop: 1, '€': labels },
{ loop: 1, $: labels },
FunctionStatement.Disallow,
parser.tokenIndex
);
Expand Down Expand Up @@ -1377,7 +1377,7 @@ export function parseTryStatement(
const isLexical: number = context & Context.OptionsLexical;
const blockScope = isLexical ? inheritScope(scope, ScopeType.Block) : {};

const block = parseBlock(parser, context, blockScope, { '€': labels }, parser.tokenIndex);
const block = parseBlock(parser, context, blockScope, { $: labels }, parser.tokenIndex);
const { tokenIndex } = parser;
const handler = consumeOpt(parser, context | Context.AllowRegExp, Token.CatchKeyword)
? parseCatchBlock(parser, context, scope, labels, isLexical, tokenIndex)
Expand All @@ -1388,7 +1388,7 @@ export function parseTryStatement(
if (parser.token === Token.FinallyKeyword) {
nextToken(parser, context | Context.AllowRegExp);
const finalizerScope = isLexical ? inheritScope(scope, ScopeType.Block) : {};
finalizer = parseBlock(parser, context, finalizerScope, { '€': labels }, tokenIndex);
finalizer = parseBlock(parser, context, finalizerScope, { $: labels }, tokenIndex);
}

if (!handler && !finalizer) {
Expand Down Expand Up @@ -1441,7 +1441,7 @@ export function parseCatchBlock(
if (isLexical) secondScope = inheritScope(scope, ScopeType.Block);
}

const body = parseBlock(parser, context, secondScope, { '€': labels }, parser.tokenIndex);
const body = parseBlock(parser, context, secondScope, { $: labels }, parser.tokenIndex);

return finishNode(parser, context, start, {
type: 'CatchClause',
Expand Down Expand Up @@ -2986,7 +2986,7 @@ export function parseFunctionBody(
context & Context.Strict &&
(context & Context.InGlobal) === 0
)
verifyArguments(parser, scope.lex['#']);
verifyArguments(parser, scope.lexicals['$']);
}

while (parser.token !== Token.RightBrace) {
Expand Down Expand Up @@ -5276,7 +5276,7 @@ export function parseMethodFormals(
report(parser, Errors.AccessorWrongArgs, 'Setter', 'one', '');
}

if (context & Context.OptionsLexical) verifyArguments(parser, scope.lex);
if (context & Context.OptionsLexical) verifyArguments(parser, scope.lexicals);
}

consume(parser, context, Token.RightParen);
Expand Down Expand Up @@ -5773,7 +5773,7 @@ export function parseFormalParametersOrFormalList(
if (isComplex) parser.flags |= Flags.SimpleParameterList;

if (context & Context.OptionsLexical && (isComplex || context & Context.Strict)) {
verifyArguments(parser, scope.lex);
verifyArguments(parser, scope.lexicals);
}

consume(parser, context, Token.RightParen);
Expand Down
78 changes: 42 additions & 36 deletions src/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const enum ScopeMasks {
*/
export interface ScopeState {
var: any;
lexvar: any;
lex: any;
lexicalVariables: any;
lexicals: any;
funcs?: any;
}

Expand All @@ -36,8 +36,8 @@ export interface ScopeState {
export function initblockScope(): ScopeState {
return {
var: {},
lexvar: {},
lex: { funcs: [] }
lexicalVariables: {},
lexicals: { funcs: [] }
};
}

Expand All @@ -50,11 +50,11 @@ export function initblockScope(): ScopeState {
export function inheritScope(scope: any, type: ScopeType): ScopeState {
return {
var: scope.var,
lexvar: {
'#': scope.lexvar
lexicalVariables: {
$: scope.lexicalVariables
},
lex: {
'#': scope.lex,
lexicals: {
$: scope.lexicals,
type,
funcs: []
}
Expand All @@ -79,10 +79,10 @@ export function declareName(
): void {
if (scope === null) return;

let hashed = '#' + name;
let hashed = '$' + name;

if (bindingType & BindingType.Variable) {
let lex = scope.lex;
let lex = scope.lexicals;

while (lex !== undefined) {
if (lex[hashed] !== undefined) {
Expand All @@ -95,36 +95,36 @@ export function declareName(
} else if (
(lex.type & ScopeType.ArgList) === 0 &&
((context & Context.OptionsWebCompat) === 0 ||
(scope.lex.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
(scope.lexicals.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
context & Context.Strict)
)
report(parser, Errors.DuplicateBinding, name);
}

lex = lex['#'];
lex = lex['$'];
}

scope.var[hashed] = scope.var[hashed] ? ScopeMasks.Undeclared : ScopeMasks.Redeclared;

let lexvar = scope.lexvar;
let lexicalVariables = scope.lexicalVariables;

while (lexvar !== undefined) {
lexvar[hashed] = ScopeMasks.Redeclared;
while (lexicalVariables !== undefined) {
lexicalVariables[hashed] = ScopeMasks.Redeclared;

lexvar = lexvar['#'];
lexicalVariables = lexicalVariables['$'];
}
} else {
let lex = scope.lex;
let lex = scope.lexicals;

if (dupeChecks) {
let lexParent = scope.lex['#'];
let lexParent = scope.lexicals['$'];

if (lexParent && lexParent.type & (ScopeType.ArgList | ScopeType.Catch) && lexParent[hashed]) {
report(parser, Errors.DuplicateBinding, name);
} else if (scope.lexvar[hashed]) {
} else if (scope.lexicalVariables[hashed]) {
if (
(context & Context.OptionsWebCompat) === 0 ||
(scope.lex.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
(scope.lexicals.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
(context & Context.Strict) !== 0
) {
report(parser, Errors.DuplicateBinding, name);
Expand All @@ -134,7 +134,7 @@ export function declareName(
if (
lex[hashed] !== undefined &&
((context & Context.OptionsWebCompat) === 0 ||
(scope.lex.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
(scope.lexicals.funcs[hashed] & ScopeMasks.Undeclared) === 0 ||
context & Context.Strict)
) {
report(parser, Errors.DuplicateBinding, name);
Expand Down Expand Up @@ -165,7 +165,7 @@ export function declareAndDedupe(
): void {
declareName(parser, context, scope, name, type, 1, isVarDecl);
if (scope === null) return;
if (context & Context.OptionsWebCompat) scope.lex.funcs['#' + name] = ScopeMasks.Redeclared;
if (context & Context.OptionsWebCompat) scope.lexicals.funcs['$' + name] = ScopeMasks.Redeclared;
}
export function declareUnboundVariable(
parser: ParserState,
Expand Down Expand Up @@ -193,8 +193,8 @@ export function addFunctionName(
isVarDecl: 0 | 1
): void {
declareName(parser, context, scope, name, type, 1, isVarDecl);
if (context & Context.OptionsWebCompat && !('#' + name in scope.lex.funcs)) {
scope.lex.funcs['#' + name] = ScopeMasks.Undeclared;
if (context & Context.OptionsWebCompat && !('$' + name in scope.lexicals.funcs)) {
scope.lexicals.funcs['$' + name] = ScopeMasks.Undeclared;
}
}
/**
Expand All @@ -211,16 +211,22 @@ export function checkConflictingLexicalDeclarations(
scope: any,
checkParent: 0 | 1
): boolean {
for (let key in scope.lex) {
if (key[0] === '#' && key.length > 1) {
if (scope.lex[key] > 1) report(parser, Errors.DuplicateBinding, key);
for (let key in scope.lexicals) {
if (key[0] === '$' && key.length > 1) {
if (scope.lexicals[key] > 1) report(parser, Errors.DuplicateBinding, key);

if (checkParent) {
if (scope.lex['#'] && scope.lex['#'].type & (ScopeType.ArgList | ScopeType.Catch) && scope.lex['#'][key]) {
if (
scope.lexicals['$'] &&
scope.lexicals['$'].type & (ScopeType.ArgList | ScopeType.Catch) &&
scope.lexicals['$'][key]
) {
report(parser, Errors.DuplicateBinding, key.slice(1));
} else if (
((context & Context.OptionsWebCompat) === 0 || (context & Context.Strict) !== 0 || !scope.lex.funcs[key]) &&
scope.lexvar[key]
((context & Context.OptionsWebCompat) === 0 ||
(context & Context.Strict) !== 0 ||
!scope.lexicals.funcs[key]) &&
scope.lexicalVariables[key]
) {
report(parser, Errors.DuplicateBinding, key.slice(1));
}
Expand All @@ -239,7 +245,7 @@ export function checkConflictingLexicalDeclarations(

export function verifyArguments(parser: ParserState, lex: any): void {
for (let key in lex) {
if (key[0] === '#' && key.length > 1 && lex[key] > 1) {
if (key[0] === '$' && key.length > 1 && lex[key] > 1) {
report(parser, Errors.DuplicateBinding, key.slice(1));
}
}
Expand All @@ -249,30 +255,30 @@ export function verifyArguments(parser: ParserState, lex: any): void {
* Appends a name to the `ExportedNames` of the `ExportsList`, and checks
* for duplicates
*
* @see [Link](https://tc39.github.io/ecma262/#sec-exports-static-semantics-exportednames)
* @see [Link](https://tc39.github.io/ecma262/$sec-exports-static-semantics-exportednames)
*
* @param parser Parser object
* @param name Exported name
*/
export function updateExportsList(parser: ParserState, name: string): void {
if (parser.exportedNames !== undefined && name !== '') {
if (parser.exportedNames['#' + name]) {
if (parser.exportedNames['$' + name]) {
report(parser, Errors.DuplicateExportBinding, name);
}
parser.exportedNames['#' + name] = ScopeMasks.Undeclared;
parser.exportedNames['$' + name] = ScopeMasks.Undeclared;
}
}

/**
* Appends a name to the `ExportedBindings` of the `ExportsList`,
*
* @see [Link](https://tc39.es/ecma262/#sec-exports-static-semantics-exportedbindings)
* @see [Link](https://tc39.es/ecma262/$sec-exports-static-semantics-exportedbindings)
*
* @param parser Parser object
* @param name Exported binding name
*/
export function addBindingToExports(parser: ParserState, name: string): void {
if (parser.exportedBindings !== undefined && name !== '') {
parser.exportedBindings['#' + name] = ScopeMasks.Undeclared;
parser.exportedBindings['$' + name] = ScopeMasks.Undeclared;
}
}

0 comments on commit b72ffe2

Please sign in to comment.