public void Visit(JsVariableDeclaration node) { if (node != null) { if (node.Parent is JsLexicalDeclaration) { // 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; } } }
public void Visit(JsVariableDeclaration node) { // invalid! ignore IsValid = false; }
public void Visit(JsVariableDeclaration node) { // shoudn't get here Debug.Fail("shouldn't get here"); }
private static int RelocateVar(JsBlock block, int insertAt, JsVar 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 JsVar; 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 <JsAstNode>(); 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 JsVariableDeclaration(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 JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField, }; assignments.Add(new JsBinaryOperator(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 = JsCommaOperator.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 JsForIn; 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 JsLookup(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(JsVariableDeclaration node) { // not applicable; terminate }
public void Visit(JsVariableDeclaration node) { // invalid! ignore IsValid = false; }
public void Visit(JsVariableDeclaration node) { if (node != null) { if (node.Parent is JsLexicalDeclaration) { // 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(JsBlock block, int insertAt, JsVar 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 JsVar; 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<JsAstNode>(); 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 JsVariableDeclaration(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 JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField, }; assignments.Add(new JsBinaryOperator(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 = JsCommaOperator.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 JsForIn; 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 JsLookup(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(JsVariableDeclaration 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 JsAstNode ParseIdentifierInitializer(JsToken inToken) { string variableName = null; JsAstNode 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; } JsContext idContext = m_currentToken.Clone(); JsContext context = m_currentToken.Clone(); JsContext 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); } JsVariableDeclaration result = new JsVariableDeclaration(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(JsVariableDeclaration node) { // not applicable; terminate }
public void Visit(JsVariableDeclaration node) { if (node != null) { var symbol = StartSymbol(node); // output the name (use the field is possible) Output(node.VariableField != null ? node.VariableField.ToString() : node.Identifier); MarkSegment(node, node.Name, node.Context); SetContextOutputPosition(node.Context); node.VariableField.IfNotNull(f => SetContextOutputPosition(f.OriginalContext)); m_startOfStatement = false; if (node.Initializer != null) { if (node.IsCCSpecialCase) { // we haven't output a cc_on yet -- output it now. // if we have, we really only need to output one if we had one to begin with AND // we are NOT removing unnecessary ones if (!m_outputCCOn || (node.UseCCOn && !m_settings.IsModificationAllowed(JsTreeModifications.RemoveUnnecessaryCCOnStatements))) { Output("/*@cc_on="); m_outputCCOn = true; } else { Output("/*@="); } } else { if (m_settings.OutputMode == MinifierOutputMode.MultipleLines && m_settings.IndentSize > 0) { OutputPossibleLineBreak(' '); OutputPossibleLineBreak('='); BreakLine(false); if (!m_onNewLine) { OutputPossibleLineBreak(' '); } } else { OutputPossibleLineBreak('='); } } AcceptNodeWithParens(node.Initializer, node.Initializer.Precedence == JsOperatorPrecedence.Comma); if (node.IsCCSpecialCase) { Output("@*/"); } } EndSymbol(symbol); } }
private static void ConvertAssignmentsToVarDecls(JsBinaryOperator binaryOp, List<JsVariableDeclaration> 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 JsLookup lookup = binaryOp.Operand1 as JsLookup; if (lookup != null) { var varDecl = new JsVariableDeclaration(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 JsBinaryOperator, varDecls, parser); ConvertAssignmentsToVarDecls(binaryOp.Operand2 as JsBinaryOperator, varDecls, parser); } // shouldn't ever be anything but these two operators } }
public override void Visit(JsVariableDeclaration 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(JsTreeModifications.RemoveUnnecessaryCCOnStatements)) { node.UseCCOn = !m_encounteredCCOn; m_encounteredCCOn = true; } } }