Beispiel #1
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a Parser instance with the given lexer supplying the tokens.
        /// </summary>
        /// <param name="engine"> The associated script engine. </param>
        /// <param name="lexer"> The lexical analyser that provides the tokens. </param>
        /// <param name="initialScope"> The initial variable scope. </param>
        /// <param name="options"> Options that influence the compiler. </param>
        /// <param name="context"> The context of the code (global, function or eval). </param>
        public Parser(ScriptEngine engine, Lexer lexer, Scope initialScope, CompilerOptions options, CodeContext context)
        {
            if (engine == null)
                throw new ArgumentNullException("engine");
            if (lexer == null)
                throw new ArgumentNullException("lexer");
            if (initialScope == null)
                throw new ArgumentNullException("initialScope");
            this.engine = engine;
            this.lexer = lexer;
            this.lexer.ParserExpressionState = ParserExpressionState.Literal;
            this.currentScope = this.initialScope = initialScope;
            this.methodOptimizationHints = new MethodOptimizationHints();
            this.options = options;
            this.context = context;
            this.StrictMode = options.ForceStrictMode;
            this.Consume();
        }
Beispiel #2
0
 /// <summary>
 /// Creates a parser that can read the body of a function.
 /// </summary>
 /// <param name="parser"> The parser for the parent context. </param>
 /// <param name="scope"> The function scope. </param>
 /// <param name="optimizationHints"> Hints about whether optimization is possible. </param>
 /// <returns> A new parser. </returns>
 private static Parser CreateFunctionBodyParser(Parser parser, Scope scope, MethodOptimizationHints optimizationHints)
 {
     var result = (Parser)parser.MemberwiseClone();
     result.SetInitialScope(scope);
     result.methodOptimizationHints = optimizationHints;
     result.context = CodeContext.Function;
     result.endToken = PunctuatorToken.RightBrace;
     return result;
 }
Beispiel #3
0
        /// <summary>
        /// Parses a function declaration or a function expression.
        /// </summary>
        /// <param name="functionType"> The type of function to parse. </param>
        /// <param name="parentScope"> The parent scope for the function. </param>
        /// <param name="functionName"> The name of the function (can be empty). </param>
        /// <returns> A function expression. </returns>
        private FunctionExpression ParseFunction(FunctionDeclarationType functionType, Scope parentScope, string functionName)
        {
            // Read the left parenthesis.
            this.Expect(PunctuatorToken.LeftParenthesis);

            // Create a new scope and assign variables within the function body to the scope.
            bool includeNameInScope = functionType != FunctionDeclarationType.Getter && functionType != FunctionDeclarationType.Setter;
            var scope = DeclarativeScope.CreateFunctionScope(parentScope, includeNameInScope ? functionName : string.Empty, null);

            // Replace scope and methodOptimizationHints.
            var originalScope = this.currentVarScope;
            var originalMethodOptimizationHints = this.methodOptimizationHints;
            var newMethodOptimizationHints = new MethodOptimizationHints();
            this.methodOptimizationHints = newMethodOptimizationHints;
            this.currentVarScope = scope;

            // Read zero or more arguments.
            var arguments = ParseFunctionArguments(PunctuatorToken.RightParenthesis);

            // Restore scope and methodOptimizationHints.
            this.methodOptimizationHints = originalMethodOptimizationHints;
            this.currentVarScope = originalScope;

            // Getters must have zero arguments.
            if (functionType == FunctionDeclarationType.Getter && arguments.Count != 0)
                throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Getters cannot have arguments", this.LineNumber, this.SourcePath);

            // Setters must have one argument.
            if (functionType == FunctionDeclarationType.Setter && arguments.Count != 1)
                throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Setters must have a single argument", this.LineNumber, this.SourcePath);

            // Read the right parenthesis.
            this.Expect(PunctuatorToken.RightParenthesis);

            // Record the start of the function body.
            var startPosition = this.PositionBeforeWhitespace;

            // Since the parser reads one token in advance, start capturing the function body here.
            var bodyTextBuilder = new System.Text.StringBuilder();
            var originalBodyTextBuilder = this.lexer.InputCaptureStringBuilder;
            this.lexer.InputCaptureStringBuilder = bodyTextBuilder;

            // Read the start brace.
            this.Expect(PunctuatorToken.LeftBrace);

            // This context has a nested function.
            this.methodOptimizationHints.HasNestedFunction = true;

            // Read the function body.
            var functionParser = CreateFunctionBodyParser(this, scope, newMethodOptimizationHints);
            var body = functionParser.Parse();

            // Transfer state back from the function parser.
            this.nextToken = functionParser.nextToken;
            this.lexer.StrictMode = this.StrictMode;
            this.lexer.InputCaptureStringBuilder = originalBodyTextBuilder;
            if (originalBodyTextBuilder != null)
                originalBodyTextBuilder.Append(bodyTextBuilder);

            SourceCodePosition endPosition;
            if (functionType == FunctionDeclarationType.Expression)
            {
                // The end token '}' will be consumed by the parent function.
                if (this.nextToken != PunctuatorToken.RightBrace)
                    throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Expected '}'", this.LineNumber, this.SourcePath);

                // Record the end of the function body.
                endPosition = new SourceCodePosition(this.PositionAfterWhitespace.Line, this.PositionAfterWhitespace.Column + 1);
            }
            else
            {
                // Consume the '}'.
                this.Expect(PunctuatorToken.RightBrace);

                // Record the end of the function body.
                endPosition = new SourceCodePosition(this.PositionAfterWhitespace.Line, this.PositionAfterWhitespace.Column + 1);
            }

            // Create a new function expression.
            var options = this.options.Clone();
            options.ForceStrictMode = functionParser.StrictMode;
            var context = new FunctionMethodGenerator(this.engine, scope, functionName,
                functionType, arguments,
                bodyTextBuilder.ToString(0, bodyTextBuilder.Length - 1), body,
                this.SourcePath, options);
            context.MethodOptimizationHints = functionParser.methodOptimizationHints;
            return new FunctionExpression(context);
        }