internal JsCatchScope(JsActivationObject parent, JsContext catchContext, JsSettings settings, JsParameterDeclaration catchParameter) : base(parent, catchContext, settings) { CatchParameter = catchParameter; }
public void Visit(JsParameterDeclaration node) { // invalid! ignore IsValid = false; }
public void Visit(JsParameterDeclaration node) { // nothing to do }
public virtual void Visit(JsParameterDeclaration node) { // no children }
private static void ResolveGhostedCatchParameter(JsActivationObject scope, JsParameterDeclaration catchParameter) { // check to see if the name exists in the outer variable scope. var ghostField = scope[catchParameter.Name]; if (ghostField == null) { // set up a ghost field to keep track of the relationship ghostField = new JsVariableField(JsFieldType.GhostCatch, catchParameter.Name, 0, null) { OriginalContext = catchParameter.Context }; scope.AddField(ghostField); } else if (ghostField.FieldType == JsFieldType.GhostCatch) { // there is, but it's another ghost catch variable. That's fine; just use it. // don't even flag it as ambiguous because if someone is later referencing the error variable // used in a couple catch variables, we'll say something then because other browsers will have that // variable undefined or from an outer scope. } else { // there is, and it's NOT another ghosted catch variable. Possible naming // collision in IE -- if an error happens, it will clobber the existing field's value, // although that MAY be the intention; we don't know for sure. But it IS a cross- // browser behavior difference. ghostField.IsAmbiguous = true; if (ghostField.OuterField != null) { // and to make matters worse, it's actually bound to an OUTER field // in modern browsers, but will bind to this catch variable in older // versions of IE! Definitely a cross-browser difference! // throw a cross-browser issue error. catchParameter.Context.HandleError(JsError.AmbiguousCatchVar); } } // link them so they all keep the same name going forward // (since they are named the same in the sources) catchParameter.VariableField.OuterField = ghostField; // TODO: this really should be a LIST of ghosted fields, since multiple // elements can ghost to the same field. ghostField.GhostedField = catchParameter.VariableField; // if the actual field has references, we want to bubble those up // since we're now linking those fields if (catchParameter.VariableField.RefCount > 0) { // add the catch parameter's references to the ghost field ghostField.AddReferences(catchParameter.VariableField.References); } }
public void Visit(JsParameterDeclaration node) { // we're good }
//--------------------------------------------------------------------------------------- // ParseTryStatement // // TryStatement : // 'try' Block Catch Finally // // Catch : // <empty> | 'catch' '(' Identifier ')' Block // // Finally : // <empty> | // 'finally' Block //--------------------------------------------------------------------------------------- private JsAstNode ParseTryStatement() { JsContext tryCtx = m_currentToken.Clone(); JsContext catchContext = null; JsContext finallyContext = null; JsBlock body = null; JsContext idContext = null; JsBlock handler = null; JsBlock finally_block = null; RecoveryTokenException excInFinally = null; m_blockType.Add(BlockType.Block); try { bool catchOrFinally = false; GetNextToken(); if (JsToken.LeftCurly != m_currentToken.Token) { ReportError(JsError.NoLeftCurly); } m_noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try { body = ParseBlock(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1) { // do nothing and just return the containing block, if any throw; } else { body = exc._partiallyComputedNode as JsBlock; if (body == null) { body = new JsBlock(exc._partiallyComputedNode.Context, this); body.Append(exc._partiallyComputedNode); } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } if (JsToken.Catch == m_currentToken.Token) { m_noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try { catchOrFinally = true; catchContext = m_currentToken.Clone(); GetNextToken(); if (JsToken.LeftParenthesis != m_currentToken.Token) { ReportError(JsError.NoLeftParenthesis); } GetNextToken(); if (JsToken.Identifier != m_currentToken.Token) { string identifier = JsKeyword.CanBeIdentifier(m_currentToken.Token); if (null != identifier) { idContext = m_currentToken.Clone(); } else { ReportError(JsError.NoIdentifier); } } else { idContext = m_currentToken.Clone(); } GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { if (JsToken.RightParenthesis != m_currentToken.Token) { ReportError(JsError.NoRightParenthesis); } GetNextToken(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = null; // rethrow throw; } else { if (m_currentToken.Token == JsToken.RightParenthesis) { GetNextToken(); } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } if (JsToken.LeftCurly != m_currentToken.Token) { ReportError(JsError.NoLeftCurly); } // parse the block handler = ParseBlock(); tryCtx.UpdateWith(handler.Context); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode == null) { handler = new JsBlock(CurrentPositionContext(), this); } else { handler = exc._partiallyComputedNode as JsBlock; if (handler == null) { handler = new JsBlock(exc._partiallyComputedNode.Context, this); handler.Append(exc._partiallyComputedNode); } } if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1) { throw; } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } } try { if (JsToken.Finally == m_currentToken.Token) { finallyContext = m_currentToken.Clone(); GetNextToken(); m_blockType.Add(BlockType.Finally); try { finally_block = ParseBlock(); catchOrFinally = true; } finally { m_blockType.RemoveAt(m_blockType.Count - 1); } tryCtx.UpdateWith(finally_block.Context); } } catch (RecoveryTokenException exc) { excInFinally = exc; // thrown later so we can execute code below } if (!catchOrFinally) { ReportError(JsError.NoCatch, true); finally_block = new JsBlock(CurrentPositionContext(), this); // make a dummy empty block } } finally { m_blockType.RemoveAt(m_blockType.Count - 1); } JsParameterDeclaration catchParameter = null; if (idContext != null) { catchParameter = new JsParameterDeclaration(idContext, this) { Name = idContext.Code }; } if (excInFinally != null) { excInFinally._partiallyComputedNode = new JsTryNode(tryCtx, this) { TryBlock = body, CatchContext = catchContext, CatchParameter = catchParameter, CatchBlock = handler, FinallyContext = finallyContext, FinallyBlock = finally_block }; throw excInFinally; } return new JsTryNode(tryCtx, this) { TryBlock = body, CatchContext = catchContext, CatchParameter = catchParameter, CatchBlock = handler, FinallyContext = finallyContext, FinallyBlock = finally_block }; }
private JsFunctionObject ParseFunction(JsFunctionType functionType, JsContext fncCtx) { JsLookup name = null; JsAstNodeList formalParameters = null; JsBlock body = null; bool inExpression = (functionType == JsFunctionType.Expression); JsContext paramsContext = null; GetNextToken(); // get the function name or make an anonymous function if in expression "position" if (JsToken.Identifier == m_currentToken.Token) { name = new JsLookup(m_currentToken.Clone(), this) { Name = m_scanner.Identifier }; GetNextToken(); } else { string identifier = JsKeyword.CanBeIdentifier(m_currentToken.Token); if (null != identifier) { name = new JsLookup(m_currentToken.Clone(), this) { Name = identifier }; GetNextToken(); } else { if (!inExpression) { // if this isn't a function expression, then we need to throw an error because // function DECLARATIONS always need a valid identifier name ReportError(JsError.NoIdentifier, m_currentToken.Clone(), true); // BUT if the current token is a left paren, we don't want to use it as the name. // (fix for issue #14152) if (m_currentToken.Token != JsToken.LeftParenthesis && m_currentToken.Token != JsToken.LeftCurly) { identifier = m_currentToken.Code; name = new JsLookup(CurrentPositionContext(), this) { Name = identifier }; GetNextToken(); } } } } // make a new state and save the old one List<BlockType> blockType = m_blockType; m_blockType = new List<BlockType>(16); Dictionary<string, LabelInfo> labelTable = m_labelTable; m_labelTable = new Dictionary<string, LabelInfo>(); try { // get the formal parameters if (JsToken.LeftParenthesis != m_currentToken.Token) { // we expect a left paren at this point for standard cross-browser support. // BUT -- some versions of IE allow an object property expression to be a function name, like window.onclick. // we still want to throw the error, because it syntax errors on most browsers, but we still want to // be able to parse it and return the intended results. // Skip to the open paren and use whatever is in-between as the function name. Doesn't matter that it's // an invalid identifier; it won't be accessible as a valid field anyway. bool expandedIndentifier = false; while (m_currentToken.Token != JsToken.LeftParenthesis && m_currentToken.Token != JsToken.LeftCurly && m_currentToken.Token != JsToken.Semicolon && m_currentToken.Token != JsToken.EndOfFile) { name.Context.UpdateWith(m_currentToken); GetNextToken(); expandedIndentifier = true; } // if we actually expanded the identifier context, then we want to report that // the function name needs to be an identifier. Otherwise we didn't expand the // name, so just report that we expected an open paren at this point. if (expandedIndentifier) { name.Name = name.Context.Code; name.Context.HandleError(JsError.FunctionNameMustBeIdentifier, false); } else { ReportError(JsError.NoLeftParenthesis, true); } } if (m_currentToken.Token == JsToken.LeftParenthesis) { // create the parameter list formalParameters = new JsAstNodeList(m_currentToken.Clone(), this); paramsContext = m_currentToken.Clone(); // skip the open paren GetNextToken(); // create the list of arguments and update the context while (JsToken.RightParenthesis != m_currentToken.Token) { String id = null; m_noSkipTokenSet.Add(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet); try { JsParameterDeclaration paramDecl = null; if (JsToken.Identifier != m_currentToken.Token && (id = JsKeyword.CanBeIdentifier(m_currentToken.Token)) == null) { if (JsToken.LeftCurly == m_currentToken.Token) { ReportError(JsError.NoRightParenthesis); break; } else if (JsToken.Comma == m_currentToken.Token) { // We're missing an argument (or previous argument was malformed and // we skipped to the comma.) Keep trying to parse the argument list -- // we will skip the comma below. ReportError(JsError.SyntaxError, true); } else { ReportError(JsError.SyntaxError, true); SkipTokensAndThrow(); } } else { if (null == id) { id = m_scanner.Identifier; } paramDecl = new JsParameterDeclaration(m_currentToken.Clone(), this) { Name = id, Position = formalParameters.Count }; formalParameters.Append(paramDecl); GetNextToken(); } // got an arg, it should be either a ',' or ')' if (JsToken.RightParenthesis == m_currentToken.Token) { break; } else if (JsToken.Comma == m_currentToken.Token) { // append the comma context as the terminator for the parameter paramDecl.IfNotNull(p => p.TerminatingContext = m_currentToken.Clone()); } else { // deal with error in some "intelligent" way if (JsToken.LeftCurly == m_currentToken.Token) { ReportError(JsError.NoRightParenthesis); break; } else { if (JsToken.Identifier == m_currentToken.Token) { // it's possible that the guy was writing the type in C/C++ style (i.e. int x) ReportError(JsError.NoCommaOrTypeDefinitionError); } else ReportError(JsError.NoComma); } } GetNextToken(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet, exc) == -1) throw; } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet); } } fncCtx.UpdateWith(m_currentToken); GetNextToken(); } // read the function body of non-abstract functions. if (JsToken.LeftCurly != m_currentToken.Token) ReportError(JsError.NoLeftCurly, true); m_blockType.Add(BlockType.Block); m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet); m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); try { // parse the block locally to get the exact end of function body = new JsBlock(m_currentToken.Clone(), this); body.BraceOnNewLine = m_foundEndOfLine; GetNextToken(); var possibleDirectivePrologue = true; while (JsToken.RightCurly != m_currentToken.Token) { try { // function body's are SourceElements (Statements + FunctionDeclarations) var statement = ParseStatement(true); if (possibleDirectivePrologue) { var constantWrapper = statement as JsConstantWrapper; if (constantWrapper != null && constantWrapper.PrimitiveType == JsPrimitiveType.String) { // if it's already a directive prologues, we're good to go if (!(constantWrapper is JsDirectivePrologue)) { // make the statement a directive prologue instead of a constant wrapper statement = new JsDirectivePrologue(constantWrapper.Value.ToString(), constantWrapper.Context, constantWrapper.Parser) { MayHaveIssues = constantWrapper.MayHaveIssues }; } } else if (!m_newModule) { // no longer considering constant wrappers possibleDirectivePrologue = false; } } else if (m_newModule) { // we scanned into a new module -- we might find directive prologues again possibleDirectivePrologue = true; } // add it to the body body.Append(statement); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode != null) { body.Append(exc._partiallyComputedNode); } if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1) throw; } } // make sure any important comments before the closing brace are kept AppendImportantComments(body); body.Context.UpdateWith(m_currentToken); fncCtx.UpdateWith(m_currentToken); } catch (EndOfStreamException) { // if we get an EOF here, we never had a chance to find the closing curly-brace fncCtx.HandleError(JsError.UnclosedFunction, true); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = new JsFunctionObject(fncCtx, this) { FunctionType = (inExpression ? JsFunctionType.Expression : JsFunctionType.Declaration), IdContext = name.IfNotNull(n => n.Context), Name = name.IfNotNull(n => n.Name), ParameterDeclarations = formalParameters, ParametersContext = paramsContext, Body = body }; throw; } } finally { m_blockType.RemoveAt(m_blockType.Count - 1); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet); } GetNextToken(); } finally { // restore state m_blockType = blockType; m_labelTable = labelTable; } return new JsFunctionObject(fncCtx, this) { FunctionType = functionType, IdContext = name.IfNotNull(n => n.Context), Name = name.IfNotNull(n => n.Name), ParameterDeclarations = formalParameters, ParametersContext = paramsContext, Body = body }; }
public void Visit(JsParameterDeclaration node) { // not applicable; terminate }
public void Visit(JsParameterDeclaration node) { if (node != null) { // just output the node's name Output(node.VariableField == null ? node.Name : node.VariableField.ToString()); MarkSegment(node, node.Name, node.Context); SetContextOutputPosition(node.Context); } }