Represents an enclosing context where variables are uniquely defined.
Example #1
0
 /// <summary>
 /// Creates a new Scope instance.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope, or <c>null</c> if this is
 /// the global scope. </param>
 /// <param name="declaredVariableCount"> The number of variables declared in this scope. </param>
 protected Scope(Scope parentScope, int declaredVariableCount)
 {
     this.ParentScope = parentScope;
     this.variables = new Dictionary<string, DeclaredVariable>(declaredVariableCount);
     this.CanDeclareVariables = true;
     this.ExistsAtRuntime = true;
 }
Example #2
0
 /// <summary>
 /// Creates a new VarStatement instance.
 /// </summary>
 /// <param name="labels"> The labels that are associated with this statement. </param>
 /// <param name="scope"> The scope the variables are defined within. </param>
 public VarStatement(IList<string> labels, Scope scope)
     : base(labels)
 {
     if (scope == null)
         throw new ArgumentNullException("scope");
     this.Scope = scope;
     this.declarations = new List<VariableDeclaration>(1);
 }
Example #3
0
 /// <summary>
 /// Creates a new NameExpression instance.
 /// </summary>
 /// <param name="scope"> The current scope. </param>
 /// <param name="name"> The name of the variable or member that is being referenced. </param>
 public NameExpression(Scope scope, string name)
 {
     if (scope == null)
         throw new ArgumentNullException("scope");
     if (name == null)
         throw new ArgumentNullException("name");
     this.Scope = scope;
     this.Name = name;
 }
Example #4
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>
 /// <returns> A new parser. </returns>
 private static Parser CreateFunctionBodyParser(Parser parser, Scope scope)
 {
     var result = (Parser)parser.MemberwiseClone();
     result.currentScope = result.initialScope = scope;
     result.methodOptimizationHints = new MethodOptimizationHints();
     result.context = CodeContext.Function;
     result.endToken = PunctuatorToken.RightBrace;
     result.DirectivePrologueProcessedCallback = null;
     return result;
 }
 /// <summary>
 /// Creates a new declarative scope for use inside a catch statement.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <param name="catchVariableName"> The name of the catch variable. </param>
 /// <returns> A new DeclarativeScope instance. </returns>
 internal static DeclarativeScope CreateCatchScope(Scope parentScope, string catchVariableName)
 {
     if (parentScope == null)
         throw new ArgumentNullException("parentScope", "Catch scopes must have a parent scope.");
     if (catchVariableName == null)
         throw new ArgumentNullException("catchVariableName");
     var result = new DeclarativeScope(parentScope, 0);
     result.DeclareVariable(catchVariableName);
     result.CanDeclareVariables = false;    // Only the catch variable can be declared in this scope.
     return result;
 }
 /// <summary>
 /// Creates a new declarative scope for use at runtime.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <param name="declaredVariableNames"> The names of variables that were declared in this scope. </param>
 /// <returns> A new DeclarativeScope instance. </returns>
 public static DeclarativeScope CreateRuntimeScope(Scope parentScope, string[] declaredVariableNames)
 {
     if (parentScope == null)
         throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope.");
     if (declaredVariableNames == null)
         throw new ArgumentNullException("declaredVariableNames");
     var result = new DeclarativeScope(parentScope, declaredVariableNames.Length);
     foreach (string variableName in declaredVariableNames)
         result.DeclareVariable(variableName);
     result.values = new object[result.DeclaredVariableCount];
     return result;
 }
Example #7
0
 /// <summary>
 /// Creates a new MethodGenerator instance.
 /// </summary>
 /// <param name="engine"> The script engine. </param>
 /// <param name="scope"> The initial scope. </param>
 /// <param name="source"> The source of javascript code. </param>
 /// <param name="options"> Options that influence the compiler. </param>
 protected MethodGenerator(ScriptEngine engine, Scope scope, ScriptSource source, CompilerOptions options)
 {
     if (engine == null)
         throw new ArgumentNullException("engine");
     if (scope == null)
         throw new ArgumentNullException("scope");
     if (source == null)
         throw new ArgumentNullException("source");
     if (options == null)
         throw new ArgumentNullException("options");
     this.Engine = engine;
     this.InitialScope = scope;
     this.Source = source;
     this.Options = options;
     this.StrictMode = this.Options.ForceStrictMode;
 }
 /// <summary>
 /// Creates a new declarative scope for use inside a function body.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <param name="functionName"> The name of the function.  Can be empty for an anonymous function. </param>
 /// <param name="argumentNames"> The names of each of the function arguments. </param>
 /// <returns> A new DeclarativeScope instance. </returns>
 internal static DeclarativeScope CreateFunctionScope(Scope parentScope, string functionName, IEnumerable<string> argumentNames)
 {
     if (parentScope == null)
         throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope.");
     if (functionName == null)
         throw new ArgumentNullException("functionName");
     if (argumentNames == null)
         throw new ArgumentNullException("argumentNames");
     var result = new DeclarativeScope(parentScope, 0);
     if (string.IsNullOrEmpty(functionName) == false)
         result.DeclareVariable(functionName);
     result.DeclareVariable("this");
     result.DeclareVariable("arguments");
     foreach (var argumentName in argumentNames)
         result.DeclareVariable(argumentName);
     return result;
 }
Example #9
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();
        }
Example #10
0
        //     EVAL SUPPORT
        //_________________________________________________________________________________________

        //private class EvalCacheKey
        //{
        //    public string Code;
        //    public Compiler.Scope Scope;
        //    public bool StrictMode;

        //    public override int GetHashCode()
        //    {
        //        int bitValue = 1;
        //        int hashCode = this.Code.GetHashCode();
        //        var scope = this.Scope;
        //        do
        //        {
        //            if (scope is Compiler.DeclarativeScope)
        //                hashCode ^= bitValue;
        //            scope = scope.ParentScope;
        //            bitValue *= 2;
        //        } while (scope != null);
        //        if (this.StrictMode == true)
        //            hashCode ^= bitValue;
        //        return hashCode;
        //    }

        //    public override bool Equals(object obj)
        //    {
        //        if ((obj is EvalCacheKey) == false)
        //            return false;
        //        var other = (EvalCacheKey) obj;
        //        if (this.Code != other.Code ||
        //            this.StrictMode != other.StrictMode)
        //            return false;
        //        var scope1 = this.Scope;
        //        var scope2 = other.Scope;
        //        do
        //        {
        //            if (scope1.GetType() != scope2.GetType())
        //                return false;
        //            scope1 = scope1.ParentScope;
        //            scope2 = scope2.ParentScope;
        //            if (scope1 == null && scope2 != null)
        //                return false;
        //            if (scope1 != null && scope2 == null)
        //                return false;
        //        } while (scope1 != null);
        //        return true;
        //    }
        //}

        //private Dictionary<EvalCacheKey, WeakReference> evalCache =
        //    new Dictionary<EvalCacheKey, WeakReference>();

        /// <summary>
        /// Evaluates the given javascript source code and returns the result.
        /// </summary>
        /// <param name="code"> The source code to evaluate. </param>
        /// <param name="scope"> The containing scope. </param>
        /// <param name="thisObject"> The value of the "this" keyword in the containing scope. </param>
        /// <param name="strictMode"> Indicates whether the eval statement is being called from
        /// strict mode code. </param>
        /// <returns> The value of the last statement that was executed, or <c>undefined</c> if
        /// there were no executed statements. </returns>
        internal object Eval(string code, Compiler.Scope scope, object thisObject, bool strictMode)
        {
            // Check if the cache contains the eval already.
            //var key = new EvalCacheKey() { Code = code, Scope = scope, StrictMode = strictMode };
            //WeakReference cachedEvalGenRef;
            //if (evalCache.TryGetValue(key, out cachedEvalGenRef) == true)
            //{
            //    var cachedEvalGen = (Compiler.EvalMethodGenerator)cachedEvalGenRef.Target;
            //    if (cachedEvalGen != null)
            //    {
            //        // Replace the "this object" before running.
            //        cachedEvalGen.ThisObject = thisObject;

            //        // Execute the cached code.
            //        return ((Compiler.EvalMethodGenerator)cachedEvalGen).Execute();
            //    }
            //}

            // Parse the eval string into an AST.
            var options = new Compiler.CompilerOptions()
            {
                ForceStrictMode = strictMode
            };
            var evalGen = new Jurassic.Compiler.EvalMethodGenerator(
                this,                                                   // The script engine.
                scope,                                                  // The scope to run the code in.
                new StringScriptSource(code),                           // The source code to execute.
                options,                                                // Options.
                thisObject);                                            // The value of the "this" keyword.

            // Make sure the eval cache doesn't get too big.  TODO: add some sort of LRU strategy?
            //if (evalCache.Count > 100)
            //    evalCache.Clear();

            //// Add the eval method generator to the cache.
            //evalCache[key] = new WeakReference(evalGen);

            // Compile and run the eval code.
            return(evalGen.Execute());
        }
Example #11
0
 public ScopeContext(Parser parser)
 {
     this.parser = parser;
     previousLetScope = parser.currentLetScope;
     previousVarScope = parser.currentVarScope;
 }
Example #12
0
 /// <summary>
 /// Creates a new EvalMethodGenerator instance.
 /// </summary>
 /// <param name="engine"> The script engine. </param>
 /// <param name="parentScope"> The scope of the calling code. </param>
 /// <param name="source"> The script code to execute. </param>
 /// <param name="options"> Options that influence the compiler. </param>
 /// <param name="thisObject"> The value of the "this" keyword in the calling code. </param>
 public EvalMethodGenerator(ScriptEngine engine, Scope parentScope, ScriptSource source, CompilerOptions options, object thisObject)
     : base(engine, parentScope, source, options)
 {
     this.ThisObject = thisObject;
 }
 /// <summary>
 /// Creates a new instance of a user-defined function.
 /// </summary>
 /// <param name="prototype"> The next object in the prototype chain. </param>
 /// <param name="name"> The name of the function. </param>
 /// <param name="argumentNames"> The names of the arguments. </param>
 /// <param name="parentScope"> The scope at the point the function is declared. </param>
 /// <param name="bodyText"> The source code for the function body. </param>
 /// <param name="generatedMethod"> A delegate which represents the body of the function plus any dependencies. </param>
 /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
 public UserDefinedFunction(ObjectInstance prototype, string name, IList<string> argumentNames, Scope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode)
     : base(prototype)
 {
     Init(name, argumentNames, parentScope, bodyText, generatedMethod, strictMode, true);
 }
 /// <summary>
 /// Creates a new instance of a user-defined function.
 /// </summary>
 /// <param name="prototype"> The next object in the prototype chain. </param>
 /// <param name="name"> The name of the function. </param>
 /// <param name="argumentNames"> The names of the arguments. </param>
 /// <param name="parentScope"> The scope at the point the function is declared. </param>
 /// <param name="bodyText"> The source code for the function body. </param>
 /// <param name="body"> A delegate which represents the body of the function. </param>
 /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
 internal UserDefinedFunction(ObjectInstance prototype, string name, IList<string> argumentNames, Scope parentScope, string bodyText, FunctionDelegate body, bool strictMode)
     : base(prototype)
 {
     Init(name, argumentNames, parentScope, bodyText, new GeneratedMethod(body, null), strictMode, true);
 }
        /// <summary>
        /// Initializes a user-defined function.
        /// </summary>
        /// <param name="name"> The name of the function. </param>
        /// <param name="argumentNames"> The names of the arguments. </param>
        /// <param name="parentScope"> The scope at the point the function is declared. </param>
        /// <param name="bodyText"> The source code for the function body. </param>
        /// <param name="generatedMethod"> A delegate which represents the body of the function, plus any dependencies. </param>
        /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
        /// <param name="hasInstancePrototype"> <c>true</c> if the function should have a valid
        /// "prototype" property; <c>false</c> if the "prototype" property should be <c>null</c>. </param>
        private void Init(string name, IList<string> argumentNames, Scope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode, bool hasInstancePrototype)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (argumentNames == null)
                throw new ArgumentNullException("argumentNames");
            if (bodyText == null)
                throw new ArgumentNullException("bodyText");
            if (generatedMethod == null)
                throw new ArgumentNullException("generatedMethod");
            if (parentScope == null)
                throw new ArgumentNullException("parentScope");
            this.ArgumentNames = new System.Collections.ObjectModel.ReadOnlyCollection<string>(argumentNames);
            this.BodyText = bodyText;
            this.generatedMethod = generatedMethod;
            this.body = (FunctionDelegate)this.generatedMethod.GeneratedDelegate;
            this.ParentScope = parentScope;
            this.StrictMode = strictMode;

            // Add function properties.
            this.FastSetProperty("name", name);
            this.FastSetProperty("length", argumentNames.Count);

            // The empty function doesn't have an instance prototype.
            if (hasInstancePrototype == true)
            {
                this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
                this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
            }
        }
Example #16
0
        /// <summary>
        /// Parses a with statement.
        /// </summary>
        /// <returns> An expression representing the with statement. </returns>
        private WithStatement ParseWith()
        {
            // This statement is not allowed in strict mode.
            if (this.StrictMode == true)
                throw new JavaScriptException(this.engine, "SyntaxError", "The with statement is not supported in strict mode", this.LineNumber, this.SourcePath);

            var result = new WithStatement(this.labelsForCurrentStatement);

            // Read past the "with" token.
            this.Expect(KeywordToken.With);

            // Read a left parenthesis token "(".
            this.Expect(PunctuatorToken.LeftParenthesis);

            // Keep track of the start of the statement so that source debugging works correctly.
            var start = this.PositionAfterWhitespace;

            // Read an object reference.
            var objectEnvironment = ParseExpression(PunctuatorToken.RightParenthesis);

            // Record the portion of the source document that will be highlighted when debugging.
            result.SourceSpan = new SourceCodeSpan(start, this.PositionBeforeWhitespace);

            // Read a right parenthesis token ")".
            this.Expect(PunctuatorToken.RightParenthesis);

            // Create a new scope and assign variables within the with statement to the scope.
            result.Scope = ObjectScope.CreateWithScope(this.currentScope, objectEnvironment);
            this.currentScope = result.Scope;

            // Read the body of the with statement.
            result.Body = ParseStatement();

            // Revert the scope.
            this.currentScope = this.currentScope.ParentScope;

            return result;
        }
Example #17
0
 ///// <summary>
 ///// Creates a new object scope for use inside a with statement.
 ///// </summary>
 ///// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 ///// <param name="scopeObject"> An expression that evaluates to the object to use. </param>
 ///// <returns> A new ObjectScope instance. </returns>
 //public static ObjectScope CreateWithScope(Scope parentScope, Library.ObjectInstance scopeObject)
 //{
 //    if (parentScope == null)
 //        throw new ArgumentException("With scopes must have a parent scope.");
 //    return new ObjectScope(parentScope) { ScopeObject = scopeObject, ProvidesImplicitThisValue = true };
 //}
 /// <summary>
 /// Creates a new object scope for use at runtime.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <param name="scopeObject"> An expression that evaluates to the object to use. </param>
 /// <param name="providesImplicitThisValue"> Indicates whether an implicit "this" value is
 /// supplied to function calls in this scope. </param>
 /// <param name="canDeclareVariables"> Indicates whether variables can be declared within
 /// the scope. </param>
 /// <returns> A new ObjectScope instance. </returns>
 public static ObjectScope CreateRuntimeScope(Scope parentScope, Library.ObjectInstance scopeObject, bool providesImplicitThisValue, bool canDeclareVariables)
 {
     return new ObjectScope(parentScope) { ScopeObject = scopeObject, ProvidesImplicitThisValue = providesImplicitThisValue, CanDeclareVariables = canDeclareVariables };
 }
Example #18
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);
        }
Example #19
0
 /// <summary>
 /// Sets the current scope and returns an object which can be disposed to restore the
 /// previous scope.
 /// </summary>
 /// <param name="letScope"> The new let scope. </param>
 /// <param name="varScope"> The new var scope. </param>
 /// <returns> An object which can be disposed to restore the previous scope. </returns>
 private ScopeContext CreateScopeContext(Scope letScope, Scope varScope = null)
 {
     if (letScope == null)
         throw new ArgumentNullException("letScope");
     var result = new ScopeContext(this);
     this.currentLetScope = letScope;
     if (varScope != null)
         this.currentVarScope = varScope;
     return result;
 }
Example #20
0
 /// <summary>
 /// Creates a new object scope for use inside a with statement.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <param name="scopeObject"> An expression that evaluates to the object to use. </param>
 /// <returns> A new ObjectScope instance. </returns>
 internal static ObjectScope CreateWithScope(Scope parentScope, Expression scopeObject)
 {
     if (parentScope == null)
         throw new ArgumentException("With scopes must have a parent scope.");
     return new ObjectScope(parentScope) { ScopeObjectExpression = scopeObject, ProvidesImplicitThisValue = true, CanDeclareVariables = false };
 }
Example #21
0
 /// <summary>
 /// Creates a new Scope instance.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope, or <c>null</c> if this is
 /// the global scope. </param>
 protected Scope(Scope parentScope)
     : this(parentScope, 0)
 {
 }
 /// <summary>
 /// Creates a simple variable assignment expression.
 /// </summary>
 /// <param name="scope"> The scope the variable is defined within. </param>
 /// <param name="name"> The name of the variable to set. </param>
 /// <param name="value"> The value to set the variable to. </param>
 public AssignmentExpression(Scope scope, string name, Expression value)
     : base(Operator.Assignment)
 {
     this.Push(new NameExpression(scope, name));
     this.Push(value);
 }
Example #23
0
 //     SCOPE HELPERS
 //_________________________________________________________________________________________
 /// <summary>
 /// Sets the initial scope.
 /// </summary>
 /// <param name="initialScope"> The initial scope </param>
 private void SetInitialScope(Scope initialScope)
 {
     if (initialScope == null)
         throw new ArgumentNullException("initialScope");
     this.currentLetScope = this.currentVarScope = this.initialScope = initialScope;
 }
Example #24
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;
 }
Example #25
0
 /// <summary>
 /// Creates a new ObjectScope instance.
 /// </summary>
 private ObjectScope(Scope parentScope)
     : base(parentScope)
 {
     this.ScopeObjectExpression = null;
     this.ProvidesImplicitThisValue = false;
 }
 /// <summary>
 /// Creates a new declarative scope for use inside a strict mode eval statement.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope.  Can not be <c>null</c>. </param>
 /// <returns> A new DeclarativeScope instance. </returns>
 internal static DeclarativeScope CreateEvalScope(Scope parentScope)
 {
     if (parentScope == null)
         throw new ArgumentNullException("parentScope", "Eval scopes must have a parent scope.");
     return new DeclarativeScope(parentScope, 0);
 }
Example #27
0
        /// <summary>
        /// Parses a try statement.
        /// </summary>
        /// <returns> A try-catch-finally statement. </returns>
        private TryCatchFinallyStatement ParseTry()
        {
            var result = new TryCatchFinallyStatement(this.labelsForCurrentStatement);

            // Consume the try keyword.
            this.Expect(KeywordToken.Try);

            // Parse the try block.
            result.TryBlock = ParseBlock();

            // The next token is either 'catch' or 'finally'.
            if (this.nextToken == KeywordToken.Catch)
            {
                // Consume the catch token.
                this.Expect(KeywordToken.Catch);

                // Read the left parenthesis.
                this.Expect(PunctuatorToken.LeftParenthesis);

                // Read the name of the variable to assign the exception to.
                result.CatchVariableName = this.ExpectIdentifier();
                this.ValidateVariableName(result.CatchVariableName);

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

                // Create a new scope for the catch variable.
                this.currentScope = result.CatchScope = DeclarativeScope.CreateCatchScope(this.currentScope, result.CatchVariableName);

                // Parse the statements inside the catch block.
                result.CatchBlock = ParseBlock();

                // Revert the scope.
                this.currentScope = this.currentScope.ParentScope;
            }

            if (this.nextToken == KeywordToken.Finally)
            {
                // Consume the finally token.
                this.Expect(KeywordToken.Finally);

                // Read the finally statements.
                result.FinallyBlock = ParseBlock();
            }

            // There must be a catch or finally block.
            if (result.CatchBlock == null && result.FinallyBlock == null)
                throw new JavaScriptException(this.engine, "SyntaxError", "Missing catch or finally after try", this.LineNumber, this.SourcePath);

            return result;
        }
 /// <summary>
 /// Creates a new DeclarativeScope instance.
 /// </summary>
 /// <param name="parentScope"> A reference to the parent scope, or <c>null</c> if this is
 /// the global scope. </param>
 /// <param name="declaredVariableCount"> The number of variables declared in this scope. </param>
 private DeclarativeScope(Scope parentScope, int declaredVariableCount)
     : base(parentScope, declaredVariableCount)
 {
 }
Example #29
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>
        /// <returns> A function expression. </returns>
        private FunctionExpression ParseFunction(FunctionType functionType, Scope parentScope)
        {
            if (functionType != FunctionType.Getter && functionType != FunctionType.Setter)
            {
                // Consume the function keyword.
                this.Expect(KeywordToken.Function);
            }

            // Read the function name.
            var functionName = string.Empty;
            if (functionType == FunctionType.Declaration)
            {
                functionName = this.ExpectIdentifier();
            }
            else if (functionType == FunctionType.Expression)
            {
                // The function name is optional for function expressions.
                if (this.nextToken is IdentifierToken)
                    functionName = this.ExpectIdentifier();
            }
            else if (functionType == FunctionType.Getter || functionType == FunctionType.Setter)
            {
                // Getters and setters can have any name that is allowed of a property.
                bool wasIdentifier;
                functionName = ReadPropertyName(out wasIdentifier);
            }
            else
                throw new ArgumentOutOfRangeException("functionType");
            ValidateVariableName(functionName);

            // Read the left parenthesis.
            this.Expect(PunctuatorToken.LeftParenthesis);

            // Read zero or more argument names.
            var argumentNames = new List<string>();

            // Read the first argument name.
            if (this.nextToken != PunctuatorToken.RightParenthesis)
            {
                var argumentName = this.ExpectIdentifier();
                ValidateVariableName(argumentName);
                argumentNames.Add(argumentName);
            }

            while (true)
            {
                if (this.nextToken == PunctuatorToken.Comma)
                {
                    // Consume the comma.
                    this.Consume();

                    // Read and validate the argument name.
                    var argumentName = this.ExpectIdentifier();
                    ValidateVariableName(argumentName);
                    argumentNames.Add(argumentName);
                }
                else if (this.nextToken == PunctuatorToken.RightParenthesis)
                    break;
                else
                    throw new JavaScriptException(this.engine, "SyntaxError", "Expected ',' or ')'", this.LineNumber, this.SourcePath);
            }

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

            // Setters must have one argument.
            if (functionType == FunctionType.Setter && argumentNames.Count != 1)
                throw new JavaScriptException(this.engine, "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;

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

            // Read the function body.
            var functionParser = Parser.CreateFunctionBodyParser(this, scope);
            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 == FunctionType.Expression)
            {
                // The end token '}' will be consumed by the parent function.
                if (this.nextToken != PunctuatorToken.RightBrace)
                    throw new JavaScriptException(this.engine, "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,
                includeNameInScope, argumentNames,
                bodyTextBuilder.ToString(0, bodyTextBuilder.Length - 1), body,
                this.SourcePath, options);
            context.MethodOptimizationHints = functionParser.methodOptimizationHints;
            return new FunctionExpression(context);
        }