Ejemplo n.º 1
0
 /// <summary>
 /// Creates a new FunctionMethodGenerator instance.
 /// </summary>
 /// <param name="scope"> The function scope. </param>
 /// <param name="functionName"> The name of the function. </param>
 /// <param name="declarationType"> Indicates how the function was declared. </param>
 /// <param name="arguments"> The names and default values of the arguments. </param>
 /// <param name="bodyText"> The source code of the function. </param>
 /// <param name="body"> The root of the abstract syntax tree for the body of the function. </param>
 /// <param name="scriptPath"> The URL or file system path that the script was sourced from. </param>
 /// <param name="span"> The extent of the function in the source code. </param>
 /// <param name="options"> Options that influence the compiler. </param>
 public FunctionMethodGenerator(DeclarativeScope scope, string functionName, FunctionDeclarationType declarationType,
                                IList <FunctionArgument> arguments, string bodyText, Statement body, string scriptPath, SourceCodeSpan span,
                                CompilerOptions options)
     : base(scope, new DummyScriptSource(scriptPath), options)
 {
     this.Name            = functionName;
     this.DeclarationType = declarationType;
     this.Arguments       = arguments;
     this.BodyRoot        = body;
     this.BodyText        = bodyText;
     Validate(span.StartLine, scriptPath);
 }
Ejemplo n.º 2
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);
        }