diff --git a/src/services/syntax/constants.ts b/src/services/syntax/constants.ts
index 8845af18af6..87d4a6a2c77 100644
--- a/src/services/syntax/constants.ts
+++ b/src/services/syntax/constants.ts
@@ -1,29 +1,24 @@
///
module TypeScript {
+ export const enum ParserContextFlags {
+ StrictMode = 1 << 0,
+ DisallowIn = 1 << 1,
+ Yield = 1 << 2,
+ GeneratorParameter = 1 << 3,
+
+ Mask = 0xF
+ }
+
export enum SyntaxNodeConstants {
None = 0,
- // Masks that we use to place information about a node into a single int. The first bit tells
- // us if we've computed the data for a node.
- //
- // The second bit tells us if the node is incrementally reusable if it does not
- // containe any skipped tokens, zero width tokens, regex tokens in it ("/", "/=" or "/.../"),
- // and contains no tokens that were parser generated.
- //
- // The next bit lets us know if the nodes was parsed in a strict context or node. A node can
- // only be used by the incremental parser if it is parsed in the same strict context as before.
- // last masks off the part of the int
- //
+ // The first four bit of the flags are used to store parser context flags.
// The width of the node is stored in the remainder of the int. This allows us up to 128MB
// for a node by using all 27 bits. However, in the common case, we'll use less than 27 bits
// for the width. Thus, the info will be stored in a single int in chakra.
- DataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
- IncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
- ParsedInStrictModeContext = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
- ParsedInDisallowInContext = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
- ParsedInYieldContext = 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000
- ParsedInGeneratorParameterContext = 0x00000020, // 0000 0000 0000 0000 0000 0000 0010 0000
- FullWidthShift = 1 << 6, // 1111 1111 1111 1111 1111 1111 1100 0000
+ DataComputed = 1 << 4, // 0000 0000 0000 0000 0000 0000 0001 0000
+ IncrementallyUnusableMask = 1 << 5, // 0000 0000 0000 0000 0000 0000 0010 0000
+ FullWidthShift = 1 << 6, // 1111 1111 1111 1111 1111 1111 1100 0000
}
}
\ No newline at end of file
diff --git a/src/services/syntax/parser.ts b/src/services/syntax/parser.ts
index 6b03a4721c1..924726649e1 100644
--- a/src/services/syntax/parser.ts
+++ b/src/services/syntax/parser.ts
@@ -195,11 +195,7 @@ module TypeScript.Parser {
//
// Getting this all correct is tricky and requires careful reading of the grammar to
// understand when these values should be changed versus when they should be inherited.
- var strictModeContext: boolean = false;
- var disallowInContext: boolean = false;
- var yieldContext: boolean = false;
- var generatorParameterContext: boolean = false;
- var contextFlags: number = 0;
+ var contextFlags: ParserContextFlags = 0;
// Current state of the parser. If we need to rewind we will store and reset these values as
// appropriate.
@@ -223,7 +219,7 @@ module TypeScript.Parser {
// Now, clear out our state so that our singleton parser doesn't keep things alive.
diagnostics = [];
- contextFlags = SyntaxNodeConstants.None;
+ contextFlags = 0;
fileName = undefined;
source.release();
source = undefined;
@@ -284,10 +280,7 @@ module TypeScript.Parser {
// are unaffected by strict mode. It's just the parser will decide what to do with it
// differently depending on what mode it is in.
if (node &&
- parsedInStrictModeContext(node) === strictModeContext &&
- parsedInDisallowInContext(node) === disallowInContext &&
- parsedInYieldContext(node) === yieldContext &&
- parsedInGeneratorParameterContext(node) === generatorParameterContext) {
+ parserContextFlags(node) === contextFlags) {
return node;
}
@@ -421,7 +414,7 @@ module TypeScript.Parser {
// If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is
// considered a keyword and is not an identifier.
- if (tokenKind === SyntaxKind.YieldKeyword && yieldContext) {
+ if (tokenKind === SyntaxKind.YieldKeyword && inYieldContext()) {
return false;
}
@@ -431,7 +424,7 @@ module TypeScript.Parser {
if (tokenKind <= SyntaxKind.LastFutureReservedStrictKeyword) {
// Could be a keyword or identifier. It's an identifier if we're not in strict
// mode.
- return !strictModeContext;
+ return !inStrictModeContext();
}
// If it's typescript keyword, then it's actually a javascript identifier.
@@ -633,39 +626,52 @@ module TypeScript.Parser {
throw Errors.invalidOperation();
}
- function updateContextFlags() {
- contextFlags =
- (strictModeContext ? SyntaxNodeConstants.ParsedInStrictModeContext : 0) |
- (disallowInContext ? SyntaxNodeConstants.ParsedInDisallowInContext : 0) |
- (yieldContext ? SyntaxNodeConstants.ParsedInYieldContext : 0) |
- (generatorParameterContext ? SyntaxNodeConstants.ParsedInGeneratorParameterContext : 0);
+ function setContextFlag(val: boolean, flag: ParserContextFlags) {
+ if (val) {
+ contextFlags |= flag;
+ }
+ else {
+ contextFlags &= ~flag;
+ }
}
function setStrictModeContext(val: boolean) {
- strictModeContext = val;
- updateContextFlags();
+ setContextFlag(val, ParserContextFlags.StrictMode);
}
function setDisallowInContext(val: boolean) {
- disallowInContext = val;
- updateContextFlags();
+ setContextFlag(val, ParserContextFlags.DisallowIn);
}
function setYieldContext(val: boolean) {
- yieldContext = val;
- updateContextFlags();
+ setContextFlag(val, ParserContextFlags.Yield);
}
function setGeneratorParameterContext(val: boolean) {
- generatorParameterContext = val;
- updateContextFlags();
+ setContextFlag(val, ParserContextFlags.GeneratorParameter);
+ }
+
+ function inStrictModeContext() {
+ return (contextFlags & ParserContextFlags.StrictMode) !== 0;
+ }
+
+ function inDisallowInContext() {
+ return (contextFlags & ParserContextFlags.DisallowIn) !== 0;
+ }
+
+ function inYieldContext() {
+ return (contextFlags & ParserContextFlags.Yield) !== 0;
+ }
+
+ function inGeneratorParameterContext() {
+ return (contextFlags & ParserContextFlags.GeneratorParameter) !== 0;
}
function parseSourceUnit(): SourceUnitSyntax {
// Note: saving and restoring the 'isInStrictMode' state is not really necessary here
// (as it will never be read afterwards). However, for symmetry with the rest of the
// parsing code, we do the same here.
- var savedIsInStrictMode = strictModeContext
+ var savedIsInStrictMode = inStrictModeContext()
// Note: any skipped tokens produced after the end of all the module elements will be
// added as skipped trivia to the start of the EOF token.
@@ -692,7 +698,7 @@ module TypeScript.Parser {
}
function updateStrictModeState(items: any[]): void {
- if (!strictModeContext) {
+ if (!inStrictModeContext()) {
// Check if all the items are directive prologue elements.
for (var i = 0, n = items.length; i < n; i++) {
if (!isDirectivePrologueElement(items[i])) {
@@ -972,7 +978,7 @@ module TypeScript.Parser {
}
function allowInAnd(func: () => T): T {
- if (disallowInContext) {
+ if (inDisallowInContext()) {
setDisallowInContext(false);
var result = func();
setDisallowInContext(true);
@@ -984,7 +990,7 @@ module TypeScript.Parser {
}
function disallowInAnd(func: () => T): T {
- if (disallowInContext) {
+ if (inDisallowInContext()) {
// no need to do anything special if 'in' is already disallowed.
return func();
}
@@ -996,7 +1002,7 @@ module TypeScript.Parser {
}
function enterYieldContextAnd(func: () => T): T {
- if (yieldContext) {
+ if (inYieldContext()) {
// no need to do anything special if we're already in the [Yield] context.
return func();
}
@@ -1008,7 +1014,7 @@ module TypeScript.Parser {
}
function exitYieldContextAnd(func: () => T): T {
- if (yieldContext) {
+ if (inYieldContext()) {
setYieldContext(false);
var result = func();
setYieldContext(true);
@@ -1108,7 +1114,7 @@ module TypeScript.Parser {
// [+GeneratorParameter] ClassHeritageopt { ClassBodyopt }
if (isHeritageClause()) {
- return isClassHeritageClause && generatorParameterContext
+ return isClassHeritageClause && inGeneratorParameterContext()
? exitYieldContextAnd(parseHeritageClausesWorker)
: parseHeritageClausesWorker();
}
@@ -1143,7 +1149,7 @@ module TypeScript.Parser {
// [+GeneratorParameter] ClassHeritageopt { ClassBodyopt }
if (openBraceToken.fullWidth() > 0) {
- return generatorParameterContext
+ return inGeneratorParameterContext()
? exitYieldContextAnd(parseClassElements)
: parseClassElements();
}
@@ -2446,11 +2452,11 @@ module TypeScript.Parser {
if (_currentToken.kind === SyntaxKind.YieldKeyword) {
// If we have a 'yield' keyword, and htis is a context where yield expressions are
// allowed, then definitely parse out a yield expression.
- if (yieldContext) {
+ if (inYieldContext()) {
return true;
}
- if (strictModeContext) {
+ if (inStrictModeContext()) {
// If we're in strict mode, then 'yield' is a keyword, could only ever start
// a yield expression.
return true;
@@ -2583,7 +2589,7 @@ module TypeScript.Parser {
}
// also, if it's the 'in' operator, only allow if our caller allows it.
- if (tokenKind === SyntaxKind.InKeyword && disallowInContext) {
+ if (tokenKind === SyntaxKind.InKeyword && inDisallowInContext()) {
break;
}
@@ -3140,7 +3146,7 @@ module TypeScript.Parser {
//
// [Yield], on the other hand, is available, and is passed through.
- var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ true, /*yield:*/ yieldContext, /*generatorParameter:*/ false);
+ var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ true, /*yield:*/ inYieldContext(), /*generatorParameter:*/ false);
if (requireArrow && currentToken().kind !== SyntaxKind.EqualsGreaterThanToken) {
return undefined;
@@ -3502,7 +3508,7 @@ module TypeScript.Parser {
var _currentToken = currentToken();
if (_currentToken.kind === SyntaxKind.OpenBracketToken) {
- return generatorParameterContext
+ return inGeneratorParameterContext()
? exitYieldContextAnd(parseComputedPropertyName)
: parseComputedPropertyName();
}
@@ -3585,17 +3591,17 @@ module TypeScript.Parser {
}
function parseFunctionBlockStatements() {
- var savedIsInStrictMode = strictModeContext;
+ var savedIsInStrictMode = inStrictModeContext();
var statements = parseSyntaxList(ListParsingState.Block_Statements, updateStrictModeState);
setStrictModeContext(savedIsInStrictMode);
return statements;
}
- function parseCallSignature(requireCompleteTypeParameterList: boolean, _yieldContext: boolean, _generatorParameterContext: boolean): CallSignatureSyntax {
+ function parseCallSignature(requireCompleteTypeParameterList: boolean, yieldContext: boolean, generatorParameterContext: boolean): CallSignatureSyntax {
return new CallSignatureSyntax(contextFlags,
tryParseTypeParameterList(requireCompleteTypeParameterList),
- parseParameterList(_yieldContext, _generatorParameterContext),
+ parseParameterList(yieldContext, generatorParameterContext),
parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false));
}
@@ -3645,7 +3651,7 @@ module TypeScript.Parser {
return new ConstraintSyntax(contextFlags, eatToken(SyntaxKind.ExtendsKeyword), parseTypeOrExpression());
}
- function parseParameterList(_yieldContext: boolean, _generatorParameterContext: boolean): ParameterListSyntax {
+ function parseParameterList(yieldContext: boolean, generatorParameterContext: boolean): ParameterListSyntax {
// FormalParameters[Yield,GeneratorParameter] :
// ...
//
@@ -3661,11 +3667,11 @@ module TypeScript.Parser {
// [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt
// [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
- var savedYieldContext = yieldContext;
- var savedGeneratorParameterContext = generatorParameterContext;
+ var savedYieldContext = inYieldContext();
+ var savedGeneratorParameterContext = inGeneratorParameterContext();
- setYieldContext(_yieldContext);
- setGeneratorParameterContext(_generatorParameterContext);
+ setYieldContext(yieldContext);
+ setGeneratorParameterContext(generatorParameterContext);
var openParenToken: ISyntaxToken;
var result = new ParameterListSyntax(contextFlags,
@@ -3747,8 +3753,8 @@ module TypeScript.Parser {
function tryParseType(): ITypeSyntax {
// The rules about 'yield' only apply to actual code/expression contexts. They don't
// apply to 'type' contexts. So we disable these parameters here before moving on.
- var savedYieldContext = yieldContext;
- var savedGeneratorParameterContext = generatorParameterContext;
+ var savedYieldContext = inYieldContext();
+ var savedGeneratorParameterContext = inGeneratorParameterContext();
setYieldContext(false);
setGeneratorParameterContext(false);
@@ -3997,7 +4003,7 @@ module TypeScript.Parser {
// [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt
// [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
- var identifier = generatorParameterContext
+ var identifier = inGeneratorParameterContext()
? enterYieldContextAnd(eatIdentifierToken)
: eatIdentifierToken();
@@ -4006,7 +4012,7 @@ module TypeScript.Parser {
var equalsValueClause: EqualsValueClauseSyntax = undefined;
if (isEqualsValueClause(/*inParameter*/ true)) {
- equalsValueClause = generatorParameterContext
+ equalsValueClause = inGeneratorParameterContext()
? exitYieldContextAnd(parseEqualsValueClause)
: parseEqualsValueClause();
}
@@ -4388,7 +4394,7 @@ module TypeScript.Parser {
}
function isExpectedVariableDeclaration_VariableDeclaratorsTerminator(): boolean {
- if (disallowInContext) {
+ if (inDisallowInContext()) {
// This is the case when we're parsing variable declarations in a for/for-in statement.
var tokenKind = currentToken().kind;
diff --git a/src/services/syntax/syntaxElement.ts b/src/services/syntax/syntaxElement.ts
index fe10dcb23f9..e14ecf33b69 100644
--- a/src/services/syntax/syntaxElement.ts
+++ b/src/services/syntax/syntaxElement.ts
@@ -17,40 +17,29 @@ module TypeScript {
return undefined;
}
- export function parsedInStrictModeContext(node: ISyntaxNode): boolean {
+ export function parserContextFlags(node: ISyntaxNode): ParserContextFlags {
var info = node.__data;
if (info === undefined) {
- return false;
+ return 0;
}
- return (info & SyntaxNodeConstants.ParsedInStrictModeContext) !== 0;
+ return info & ParserContextFlags.Mask;
+ }
+
+ export function parsedInStrictModeContext(node: ISyntaxNode): boolean {
+ return (parserContextFlags(node) & ParserContextFlags.StrictMode) !== 0;
}
export function parsedInDisallowInContext(node: ISyntaxNode): boolean {
- var info = node.__data;
- if (info === undefined) {
- return false;
- }
-
- return (info & SyntaxNodeConstants.ParsedInDisallowInContext) !== 0;
+ return (parserContextFlags(node) & ParserContextFlags.DisallowIn) !== 0;
}
export function parsedInYieldContext(node: ISyntaxNode): boolean {
- var info = node.__data;
- if (info === undefined) {
- return false;
- }
-
- return (info & SyntaxNodeConstants.ParsedInYieldContext) !== 0;
+ return (parserContextFlags(node) & ParserContextFlags.Yield) !== 0;
}
export function parsedInGeneratorParameterContext(node: ISyntaxNode): boolean {
- var info = node.__data;
- if (info === undefined) {
- return false;
- }
-
- return (info & SyntaxNodeConstants.ParsedInGeneratorParameterContext) !== 0;
+ return (parserContextFlags(node) & ParserContextFlags.GeneratorParameter) !== 0;
}
export function previousToken(token: ISyntaxToken): ISyntaxToken {