protected UnaryOperator(Context context, JSParser parser, AstNode operand, JSToken operatorToken) : base(context, parser) { Operand = operand; OperatorToken = operatorToken; if (Operand != null) Operand.Parent = this; }
public SwitchCase(Context context, JSParser parser, AstNode caseValue, Block statements) : base(context, parser) { m_caseValue = caseValue; if (caseValue != null) { caseValue.Parent = this; } if (statements != null) { if (statements.Count == 1) { // if there is only one item in the block // and that one item IS a block... Block block = statements[0] as Block; if (block != null) { // then we can skip the intermediary block because all it // does is add braces around the block, which aren't needed statements = block; } } } m_statements = statements; if (statements != null) { statements.Parent = this; } }
internal JScriptException(JSError errorNumber, Context context) { m_valueObject = Missing.Value; m_context = (context == null ? null : context.Clone()); m_fileContext = (context == null ? null : context.Document.FileContext); m_code = HResult = unchecked((int)(0x800A0000 + (int)errorNumber)); }
public ObjectLiteral(Context context, JSParser parser, ObjectLiteralField[] keys, AstNode[] values) : base(context, parser) { // the length of keys and values should be identical. // if either is null, or if the lengths don't match, we ignore both! if (keys == null || values == null || keys.Length != values.Length) { // allocate EMPTY arrays so we don't have to keep checking for nulls m_keys = new ObjectLiteralField[0]; m_values = new AstNode[0]; } else { // copy the arrays m_keys = keys; m_values = values; // make sure the parents are set properly foreach (AstNode astNode in keys) { astNode.Parent = this; } foreach (AstNode astNode in values) { astNode.Parent = this; } // because we don't ensure that the arrays are the same length, we'll need to // check for the minimum length every time we iterate over them } }
//public Dictionary<JSToken, int> TokenCounts; public JSScanner(Context sourceContext) { m_keywords = s_Keywords; m_previousToken = JSToken.None; EatUnnecessaryCCOn = true; UsePreprocessorDefines = true; SetSource(sourceContext); }
public Switch(Context context, JSParser parser, AstNode expression, AstNodeList cases) : base(context, parser) { Expression = expression; Cases = cases; if (Expression != null) Expression.Parent = this; if (Cases != null) Cases.Parent = this; }
public ConstantWrapper(Object value, PrimitiveType primitiveType, Context context, JSParser parser) : base(context, parser) { PrimitiveType = primitiveType; // force numerics to be of type double Value = (primitiveType == PrimitiveType.Number ? System.Convert.ToDouble(value, CultureInfo.InvariantCulture) : value); }
public DoWhile(Context context, JSParser parser, AstNode body, AstNode condition) : base(context, parser) { Body = ForceToBlock(body); Condition = condition; if (Body != null) Body.Parent = this; if (Condition != null) Condition.Parent = this; }
public ConditionalCompilationElseIf(Context context, JSParser parser, AstNode condition) : base(context, parser) { Condition = condition; if (Condition != null) { Condition.Parent = this; } }
public WithNode(Context context, JSParser parser, AstNode obj, AstNode body) : base(context, parser) { m_withObject = obj; Body = ForceToBlock(body); if (m_withObject != null) { m_withObject.Parent = this; } if (Body != null) { Body.Parent = this; } }
public Member(Context context, JSParser parser, AstNode rootObject, string memberName, Context idContext) : base(context, parser) { Name = memberName; NameContext = idContext; Root = rootObject; if (Root != null) Root.Parent = this; }
public Conditional(Context context, JSParser parser, AstNode condition, AstNode trueExpression, AstNode falseExpression) : base(context, parser) { Condition = condition; TrueExpression = trueExpression; FalseExpression = falseExpression; if (condition != null) condition.Parent = this; if (trueExpression != null) trueExpression.Parent = this; if (falseExpression != null) falseExpression.Parent = this; }
public ForIn(Context context, JSParser parser, AstNode var, AstNode collection, AstNode body) : base(context, parser) { Variable = var; Collection = collection; Body = ForceToBlock(body); if (Body != null) Body.Parent = this; if (Variable != null) Variable.Parent = this; if (Collection != null) Collection.Parent = this; }
public ForNode(Context context, JSParser parser, AstNode initializer, AstNode condition, AstNode increment, AstNode body) : base(context, parser) { Initializer = initializer; Condition = condition; Incrementer = increment; Body = ForceToBlock(body); if (Body != null) Body.Parent = this; if (Incrementer != null) Incrementer.Parent = this; if (Condition != null) Condition.Parent = this; if (Initializer != null) Initializer.Parent = this; }
public IfNode(Context context, JSParser parser, AstNode condition, AstNode trueBranch, AstNode falseBranch) : base(context, parser) { Condition = condition; TrueBlock = ForceToBlock(trueBranch); FalseBlock = ForceToBlock(falseBranch); // make sure the parent element is set if (Condition != null) Condition.Parent = this; if (TrueBlock != null) TrueBlock.Parent = this; if (FalseBlock != null) FalseBlock.Parent = this; }
public LabeledStatement(Context context, JSParser parser, string label, int nestCount, AstNode statement) : base(context, parser) { m_label = label; m_statement = statement; m_nestCount = nestCount; if (m_statement != null) { m_statement.Parent = this; } }
public TryNode(Context context, JSParser parser, AstNode tryBlock, string catchVarName, Context catchVarContext, AstNode catchBlock, AstNode finallyBlock) : base(context, parser) { CatchVarName = catchVarName; TryBlock = ForceToBlock(tryBlock); CatchBlock = ForceToBlock(catchBlock); FinallyBlock = ForceToBlock(finallyBlock); if (TryBlock != null) { TryBlock.Parent = this; } if (CatchBlock != null) { CatchBlock.Parent = this; } if (FinallyBlock != null) { FinallyBlock.Parent = this; } CatchVarContext = catchVarContext; }
public CallNode(Context context, JSParser parser, AstNode function, AstNodeList args, bool inBrackets) : base(context, parser) { m_func = function; m_args = args; m_inBrackets = inBrackets; if (m_func != null) { m_func.Parent = this; } if (m_args != null) { m_args.Parent = this; } }
//--------------------------------------------------------------------------------------- // ParseFunction // // FunctionDeclaration : // VisibilityModifier 'function' Identifier '(' // FormalParameterList ')' '{' FunctionBody '}' // // FormalParameterList : // <empty> | // IdentifierList Identifier // // IdentifierList : // <empty> | // Identifier, IdentifierList //--------------------------------------------------------------------------------------- private FunctionObject ParseFunction(FunctionType functionType, Context fncCtx) { Lookup name = null; List<ParameterDeclaration> formalParameters = null; Block body = null; bool inExpression = (functionType == FunctionType.Expression); GetNextToken(); // get the function name or make an anonymous function if in expression "position" if (JSToken.Identifier == m_currentToken.Token) { name = new Lookup(m_scanner.GetIdentifier(), m_currentToken.Clone(), this); GetNextToken(); } else { string identifier = JSKeyword.CanBeIdentifier(m_currentToken.Token); if (null != identifier) { name = new Lookup(identifier, m_currentToken.Clone(), this); 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, 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 Lookup(identifier, CurrentPositionContext(), this); 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>(); // create the function scope and stick it onto the scope stack FunctionScope functionScope = new FunctionScope( ScopeStack.Peek(), (functionType != FunctionType.Declaration), this ); ScopeStack.Push(functionScope); 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 indentifier. Otherwise we didn't expand the // name, so just report that we expected an open parent at this point. if (expandedIndentifier) { name.Name = name.Context.Code; name.Context.HandleError(JSError.FunctionNameMustBeIdentifier, true); } else { ReportError(JSError.NoLeftParenthesis, true); } } if (m_currentToken.Token == JSToken.LeftParenthesis) { // skip the open paren GetNextToken(); Context paramArrayContext = null; formalParameters = new List<ParameterDeclaration>(); // create the list of arguments and update the context while (JSToken.RightParenthesis != m_currentToken.Token) { if (paramArrayContext != null) { ReportError(JSError.ParameterListNotLast, paramArrayContext, true); paramArrayContext = null; } String id = null; m_noSkipTokenSet.Add(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet); try { 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.GetIdentifier(); } Context paramCtx = m_currentToken.Clone(); GetNextToken(); formalParameters.Add(new ParameterDeclaration(paramCtx, this, id, formalParameters.Count)); } // got an arg, it should be either a ',' or ')' if (JSToken.RightParenthesis == m_currentToken.Token) break; else if (JSToken.Comma != m_currentToken.Token) { // 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 Block(m_currentToken.Clone(), this); GetNextToken(); while (JSToken.RightCurly != m_currentToken.Token) { try { // function body's are SourceElements (Statements + FunctionDeclarations) body.Append(ParseStatement(true)); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode != null) { body.Append(exc._partiallyComputedNode); } if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1) throw; } } body.Context.UpdateWith(m_currentToken); fncCtx.UpdateWith(m_currentToken); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = new FunctionObject( name, this, (inExpression ? FunctionType.Expression : FunctionType.Declaration), formalParameters == null ? null : formalParameters.ToArray(), body, fncCtx, functionScope ); throw; } } finally { m_blockType.RemoveAt(m_blockType.Count - 1); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet); } GetNextToken(); } finally { // pop the scope off the stack ScopeStack.Pop(); // restore state m_blockType = blockType; m_labelTable = labelTable; } return new FunctionObject( name, this, functionType, formalParameters == null ? null : formalParameters.ToArray(), body, fncCtx, functionScope); }
Block ParseBlock(out Context closingBraceContext) { closingBraceContext = null; m_blockType.Add(BlockType.Block); Block codeBlock = new Block(m_currentToken.Clone(), this); GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet); try { try { while (JSToken.RightCurly != m_currentToken.Token) { try { // pass false because we really only want Statements, and FunctionDeclarations // are technically not statements. We'll still handle them, but we'll issue a warning. codeBlock.Append(ParseStatement(false)); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode != null) codeBlock.Append(exc._partiallyComputedNode); if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1) throw; } } } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = codeBlock; throw; } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_blockType.RemoveAt(m_blockType.Count - 1); } closingBraceContext = m_currentToken.Clone(); // update the block context codeBlock.Context.UpdateWith(m_currentToken); GetNextToken(); return codeBlock; }
private int IndexOfToken(JSToken[] tokens, JSToken token) { int i, c; for (i = 0, c = tokens.Length; i < c; i++) if (tokens[i] == token) break; if (i >= c) i = -1; else { // assume that the caller will deal with the token so move the state back to normal m_errorToken = null; } return i; }
private void SkipTokensAndThrow(AstNode partialAST) { m_errorToken = null; // make sure we go to the next token bool checkForEndOfLine = m_noSkipTokenSet.HasToken(JSToken.EndOfLine); while (!m_noSkipTokenSet.HasToken(m_currentToken.Token)) { if (checkForEndOfLine) { if (m_scanner.GotEndOfLine) { m_errorToken = m_currentToken; throw new RecoveryTokenException(JSToken.EndOfLine, partialAST); } } GetNextToken(); if (++m_tokensSkipped > c_MaxSkippedTokenNumber) { ForceReportInfo(JSError.TooManyTokensSkipped); throw new EndOfFileException(); } if (JSToken.EndOfFile == m_currentToken.Token) throw new EndOfFileException(); } m_errorToken = m_currentToken; // got a token in the no skip set, throw throw new RecoveryTokenException(m_currentToken.Token, partialAST); }
//--------------------------------------------------------------------------------------- // ForceReportInfo // // Generate a parser error (info), does not change the error state in the parse //--------------------------------------------------------------------------------------- private static void ForceReportInfo(Context context, JSError errorId) { Debug.Assert(context != null); context.HandleError(errorId); }
public void SetSource(Context sourceContext) { if (sourceContext == null) { throw new ArgumentException(StringMgr.GetString("InternalCompilerError")); } m_strSourceCode = sourceContext.Document.Source; m_startPos = sourceContext.StartPosition; StartLinePosition = sourceContext.StartLinePosition; m_endPos = (0 < sourceContext.EndPosition && sourceContext.EndPosition < m_strSourceCode.Length) ? sourceContext.EndPosition : m_strSourceCode.Length; m_currentToken = sourceContext; m_escapedString = null; m_identifier = new StringBuilder(128); m_idLastPosOnBuilder = 0; m_currentPos = m_startPos; CurrentLine = (sourceContext.StartLineNumber > 0) ? sourceContext.StartLineNumber : 1; GotEndOfLine = false; //TokenCounts = new Dictionary<JSToken, int>(); }
public RegExpLiteral(string pattern, string patternSwitches, Context context, JSParser parser) : base(context, parser) { Pattern = pattern; PatternSwitches = patternSwitches; }
//--------------------------------------------------------------------------------------- // ParseStatements // // statements : // <empty> | // statement statements // //--------------------------------------------------------------------------------------- private Block ParseStatements() { m_program = new Block(m_sourceContext.Clone(), this); m_blockType.Add(BlockType.Block); m_errorToken = null; try { GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_noSkipTokenSet.Add(NoSkipTokenSet.s_TopLevelNoSkipTokenSet); try { while (m_currentToken.Token != JSToken.EndOfFile) { AstNode ast = null; try { // parse a statement -- pass true because we really want a SourceElement, // which is a Statement OR a FunctionDeclaration. Technically, FunctionDeclarations // are not statements! ast = ParseStatement(true); } catch (RecoveryTokenException exc) { if (TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, exc) || TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc)) { ast = exc._partiallyComputedNode; GetNextToken(); } else { m_errorToken = null; do { GetNextToken(); } while (m_currentToken.Token != JSToken.EndOfFile && !TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, m_currentToken.Token) && !TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, m_currentToken.Token)); } } if (null != ast) m_program.Append(ast); } if (m_scanner.HasImportantComments && m_settings.PreserveImportantComments && m_settings.IsModificationAllowed(TreeModifications.PreserveImportantComments)) { // we have important comments before the EOF. Add the comment(s) to the program. Context commentContext; while((commentContext = m_scanner.PopImportantComment()) != null) { m_program.Append(new ImportantComment(commentContext, this)); } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_TopLevelNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); } } catch (EndOfFileException) { } catch (ScannerException se) { // a scanner exception implies that the end of file has been reached with an error. // Mark the end of file as the error location EOFError(se.Error); } return m_program; }
internal JSToken PeekToken() { int thisCurrentPos = m_currentPos; int thisCurrentLine = CurrentLine; int thisStartLinePos = StartLinePosition; bool thisGotEndOfLine = GotEndOfLine; int thisLastPosOnBuilder = m_idLastPosOnBuilder; m_peekModeOn = true; JSToken token; // temporary switch the token Context thisCurrentToken = m_currentToken; m_currentToken = m_currentToken.Clone(); try { GetNextToken(); token = m_currentToken.Token; } finally { m_currentToken = thisCurrentToken; m_currentPos = thisCurrentPos; CurrentLine = thisCurrentLine; StartLinePosition = thisStartLinePos; GotEndOfLine = thisGotEndOfLine; m_identifier.Length = 0; m_idLastPosOnBuilder = thisLastPosOnBuilder; m_peekModeOn = false; m_escapedString = null; } return token; }
//--------------------------------------------------------------------------------------- // GetNextToken // // Return the next token or peeked token if this.errorToken is not null. // Usually this.errorToken is set by AddError even though any code can look ahead // by assigning this.errorToken. // At this point the context is not saved so if position information is needed // they have to be saved explicitely //--------------------------------------------------------------------------------------- private void GetNextToken() { try { if (null != m_errorToken) { if (m_breakRecursion > 10) { m_errorToken = null; m_scanner.GetNextToken(); return; } m_breakRecursion++; m_currentToken = m_errorToken; m_errorToken = null; } else { m_goodTokensProcessed++; m_breakRecursion = 0; // the scanner shares this.currentToken with the parser m_scanner.GetNextToken(); } } catch (ScannerException e) { if (e.Error != JSError.NoCommentEnd) { // rethrow anything that isn't an unterminated comment throw; } else { m_currentToken.Token = JSToken.EndOfFile; m_currentToken.HandleError(JSError.NoCommentEnd); } } }
protected Expression(Context context, JSParser parser) : base(context, parser) { }
//--------------------------------------------------------------------------------------- // ReportError // // Generate a parser error. // The function is told whether or not next call to GetToken() should return the same // token or not //--------------------------------------------------------------------------------------- private void ReportError(JSError errorId, Context context, bool skipToken) { Debug.Assert(context != null); int previousSeverity = m_severity; m_severity = (new JScriptException(errorId)).Severity; // EOF error is special and it's the last error we can possibly get if (JSToken.EndOfFile == context.Token) EOFError(errorId); // EOF context is special else { // report the error if not in error condition and the // error for this token is not worse than the one for the // previous token if (m_goodTokensProcessed > 0 || m_severity < previousSeverity) context.HandleError(errorId); // reset proper info if (skipToken) m_goodTokensProcessed = -1; else { m_errorToken = m_currentToken; m_goodTokensProcessed = 0; } } }