public void Visit(VariableDeclaration node) { // invalid! ignore IsValid = false; }
public void Visit(VariableDeclaration node) { if (node != null) { if (node.Parent is LexicalDeclaration) { // ES6 let or const declaration. Only add to the current lexical scope. CurrentLexicalScope.LexicallyDeclaredNames.Add(node); } else { // must be var or const (mozilla-style). Add to both the lexical scope // and the variable scope. The variable scope will actually use this node // to create a field; the lexical stack will just use it to detect conflicts // with lex-decls CurrentLexicalScope.VarDeclaredNames.Add(node); CurrentVariableScope.VarDeclaredNames.Add(node); } if (node.Initializer != null) { // recurse the initializer node.Initializer.Accept(this); node.Index = NextOrderIndex; } else { // no initializer; give it an index of -1 because it doesn't actually // do anything at execution time. node.Index = -1; } } }
private static int RelocateVar(Block block, int insertAt, Var varStatement) { // if the var statement is at the next position to insert, then we don't need // to do anything. if (block[insertAt] != varStatement) { // check to see if the current position is a var and we are the NEXT statement. // if that's the case, we don't need to break out the initializer, just append all the // vardecls as-is to the current position. var existingVar = block[insertAt] as Var; if (existingVar != null && block[insertAt + 1] == varStatement) { // just append our vardecls to the insertion point, then delete our statement existingVar.Append(varStatement); block.RemoveAt(insertAt + 1); } else { // iterate through the decls and count how many have initializers var initializerCount = 0; for (var ndx = 0; ndx < varStatement.Count; ++ndx) { if (varStatement[ndx].Initializer != null) { ++initializerCount; } } // if there are more than two decls with initializers, then we won't actually // be gaining anything by moving the var to the top. We'll get rid of the four // bytes for the "var ", but we'll be adding two bytes for the name and comma // because name=init will still need to remain behind. if (initializerCount <= 2) { // first iterate through all the declarations in the var statement, // constructing an expression statement that is made up of assignment // operators for each of the declarations that have initializers (if any) // and removing all the initializers var assignments = new List<AstNode>(); for (var ndx = 0; ndx < varStatement.Count; ++ndx) { var varDecl = varStatement[ndx]; if (varDecl.Initializer != null) { if (varDecl.IsCCSpecialCase) { // create a vardecl with the same name and no initializer var copyDecl = new VariableDeclaration(varDecl.Context, varDecl.Parser) { Identifier = varDecl.Identifier, NameContext = varDecl.VariableField.OriginalContext, VariableField = varDecl.VariableField }; // replace the special vardecl with the copy varStatement[ndx] = copyDecl; // add the original vardecl to the list of "assignments" assignments.Add(varDecl); // add the new decl to the field's declaration list, and remove the old one // because we're going to change that to an assignment. varDecl.VariableField.Declarations.Add(copyDecl); varDecl.VariableField.Declarations.Remove(varDecl); } else { // hold on to the object so we don't lose it to the GC var initializer = varDecl.Initializer; // remove it from the vardecl varDecl.Initializer = null; // create an assignment operator for a lookup to the name // as the left, and the initializer as the right, and add it to the list var lookup = new Lookup(varDecl.VariableField.OriginalContext, varDecl.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField, }; assignments.Add(new BinaryOperator(varDecl.Context, varDecl.Parser) { Operand1 = lookup, Operand2 = initializer, OperatorToken = JSToken.Assign, OperatorContext = varDecl.AssignContext }); // add the new lookup to the field's references varDecl.VariableField.References.Add(lookup); } } } // now if there were any initializers... if (assignments.Count > 0) { // we want to create one big expression from all the assignments and replace the // var statement with the assignment(s) expression. Start at position n=1 and create // a binary operator of n-1 as the left, n as the right, and using a comma operator. var expression = assignments[0]; for (var ndx = 1; ndx < assignments.Count; ++ndx) { expression = CommaOperator.CombineWithComma(null, expression.Parser, expression, assignments[ndx]); } // replace the var with the expression. // we still have a pointer to the var, so we can insert it back into the proper // place next. varStatement.Parent.ReplaceChild(varStatement, expression); } else { // no initializers. // if the parent is a for-in statement... var forInParent = varStatement.Parent as ForIn; if (forInParent != null) { // we want to replace the var statement with a lookup for the var // there should be only one vardecl var varDecl = varStatement[0]; var lookup = new Lookup(varDecl.VariableField.OriginalContext, varStatement.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField }; varStatement.Parent.ReplaceChild(varStatement, lookup); varDecl.VariableField.References.Add(lookup); } else { // just remove the var statement altogether varStatement.Parent.ReplaceChild(varStatement, null); } } // if the statement at the insertion point is a var-statement already, // then we just need to append our vardecls to it. Otherwise we'll insert our // var statement at the right point if (existingVar != null) { // append the varstatement we want to move to the existing var, which will // transfer all the vardecls to it. existingVar.Append(varStatement); } else { // move the var to the insert point, incrementing the position or next time block.Insert(insertAt, varStatement); } } } } return insertAt; }
public void Visit(VariableDeclaration node) { Debug.Fail("shouldn't get here"); }
//--------------------------------------------------------------------------------------- // ParseIdentifierInitializer // // Does the real work of parsing a single variable declaration. // inToken is JSToken.In whenever the potential expression that initialize a variable // cannot contain an 'in', as in the for statement. inToken is JSToken.None otherwise //--------------------------------------------------------------------------------------- private AstNode ParseIdentifierInitializer(JSToken inToken) { string variableName = null; AstNode assignmentExpr = null; RecoveryTokenException except = null; GetNextToken(); if (JSToken.Identifier != m_currentToken.Token) { String identifier = JSKeyword.CanBeIdentifier(m_currentToken.Token); if (null != identifier) { variableName = identifier; } else { // make up an identifier assume we're done with the var statement if (JSScanner.IsValidIdentifier(m_currentToken.Code)) { // it's probably just a keyword ReportError(JSError.NoIdentifier, m_currentToken.Clone(), true); variableName = m_currentToken.Code; } else { ReportError(JSError.NoIdentifier); return null; } } } else { variableName = m_scanner.Identifier; } Context idContext = m_currentToken.Clone(); Context context = m_currentToken.Clone(); Context assignContext = null; bool ccSpecialCase = false; bool ccOn = false; GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try { if (m_currentToken.Token == JSToken.ConditionalCommentStart) { ccSpecialCase = true; GetNextToken(); if (m_currentToken.Token == JSToken.ConditionalCompilationOn) { GetNextToken(); if (m_currentToken.Token == JSToken.ConditionalCommentEnd) { // forget about it; just ignore the whole thing because it's empty ccSpecialCase = false; } else { ccOn = true; } } } if (JSToken.Assign == m_currentToken.Token || JSToken.Equal == m_currentToken.Token) { assignContext = m_currentToken.Clone(); if (JSToken.Equal == m_currentToken.Token) { ReportError(JSError.NoEqual, true); } // move past the equals sign GetNextToken(); if (m_currentToken.Token == JSToken.ConditionalCommentEnd) { // so we have var id/*@ =@*/ or var id//@=<EOL> // we only support the equal sign inside conditional comments IF // the initializer value is there as well. ccSpecialCase = false; m_currentToken.HandleError(JSError.ConditionalCompilationTooComplex); GetNextToken(); } try { assignmentExpr = ParseExpression(true, inToken); } catch (RecoveryTokenException exc) { assignmentExpr = exc._partiallyComputedNode; throw; } finally { if (null != assignmentExpr) { context.UpdateWith(assignmentExpr.Context); } } } else if (ccSpecialCase) { // so we have "var id /*@" or "var id //@", but the next character is NOT an equal sign. // we don't support this structure, either. ccSpecialCase = false; m_currentToken.HandleError(JSError.ConditionalCompilationTooComplex); // skip to end of conditional comment while (m_currentToken.Token != JSToken.EndOfFile && m_currentToken.Token != JSToken.ConditionalCommentEnd) { GetNextToken(); } GetNextToken(); } // if the current token is not an end-of-conditional-comment token now, // then we're not in our special case scenario if (m_currentToken.Token == JSToken.ConditionalCommentEnd) { GetNextToken(); } else if (ccSpecialCase) { // we have "var id/*@=expr" but the next token is not the closing comment. // we don't support this structure, either. ccSpecialCase = false; m_currentToken.HandleError(JSError.ConditionalCompilationTooComplex); // the assignment expression was apparently wiothin the conditional compilation // comment, but we're going to ignore it. So clear it out. assignmentExpr = null; // skip to end of conditional comment while (m_currentToken.Token != JSToken.EndOfFile && m_currentToken.Token != JSToken.ConditionalCommentEnd) { GetNextToken(); } GetNextToken(); } } catch (RecoveryTokenException exc) { // If the exception is in the vardecl no-skip set then we successfully // recovered to the end of the declaration and can just return // normally. Otherwise we re-throw after constructing the partial result. if (IndexOfToken(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet, exc) == -1) except = exc; } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } VariableDeclaration result = new VariableDeclaration(context, this) { Identifier = variableName, NameContext = idContext, AssignContext = assignContext, Initializer = assignmentExpr }; result.IsCCSpecialCase = ccSpecialCase; if (ccSpecialCase) { // by default, set the flag depending on whether we encountered a @cc_on statement. // might be overridden by the node in analyze phase result.UseCCOn = ccOn; } if (null != except) { except._partiallyComputedNode = result; throw except; } return result; }
public void Visit(VariableDeclaration node) { // not applicable; terminate }
private static void ConvertAssignmentsToVarDecls(BinaryOperator binaryOp, List<VariableDeclaration> varDecls, JSParser parser) { // we've already checked that the tree only contains simple assignments separate by commas, // but just in case we'll check for null anyway if (binaryOp != null) { if (binaryOp.OperatorToken == JSToken.Assign) { // we've already cleared this as a simple lookup, but run the check just to be sure Lookup lookup = binaryOp.Operand1 as Lookup; if (lookup != null) { var varDecl = new VariableDeclaration(binaryOp.Context.Clone(), parser) { Identifier = lookup.Name, NameContext = lookup.Context.Clone(), AssignContext = binaryOp.OperatorContext, Initializer = binaryOp.Operand2, VariableField = lookup.VariableField }; varDecl.VariableField.Declarations.Add(varDecl); varDecls.Add(varDecl); } } else if (binaryOp.OperatorToken == JSToken.Comma) { // recurse both operands ConvertAssignmentsToVarDecls(binaryOp.Operand1 as BinaryOperator, varDecls, parser); ConvertAssignmentsToVarDecls(binaryOp.Operand2 as BinaryOperator, varDecls, parser); } // shouldn't ever be anything but these two operators } }
public override void Visit(VariableDeclaration node) { if (node != null) { base.Visit(node); // check the name of the variable for reserved words that aren't allowed if (JSScanner.IsKeyword(node.Identifier, m_scopeStack.Peek().UseStrict)) { node.Context.HandleError(JSError.KeywordUsedAsIdentifier, true); } else if (m_scopeStack.Peek().UseStrict && (string.CompareOrdinal(node.Identifier, "eval") == 0 || string.CompareOrdinal(node.Identifier, "arguments") == 0)) { // strict mode cannot declare variables named "eval" or "arguments" node.NameContext.HandleError(JSError.StrictModeVariableName, true); } // if this is a special-case vardecl (var foo/*@cc_on=EXPR@*/), set the flag indicating // we encountered a @cc_on statement if we found one if (node.IsCCSpecialCase && m_parser.Settings.IsModificationAllowed(TreeModifications.RemoveUnnecessaryCCOnStatements)) { node.UseCCOn = !m_encounteredCCOn; m_encounteredCCOn = true; } } }