Пример #1
0
        public static FunctionObject FunctionCreate(FunctionCreateKind kind, FormalParameters parameters, FunctionStatementList body, LexicalEnvironment scope, bool strict, IValue?prototype = null)
        {
            if (prototype == null)
            {
                prototype = Interpreter.Instance().CurrentRealm().Intrinsics.FunctionPrototype;
            }
            var            functionKind = kind == FunctionCreateKind.Normal ? FunctionKind.Normal : FunctionKind.NonConstructor;
            FunctionObject F            = FunctionAllocate(prototype, strict, functionKind);

            return(FunctionInitialize(F, kind, parameters, body, scope));
        }
Пример #2
0
        public static LexicalEnvironment NewFunctionalEnvironment(FunctionObject F, IValue newTarget)
        {
            if (!(newTarget is UndefinedValue) && !(newTarget is Object))
            {
                throw new InvalidOperationException("Spec 8.1.2.4 step 2");
            }
            var env    = new LexicalEnvironment();
            var envRec = new FunctionEnvironmentRecord(F, newTarget);

            env.EnvironmentRecord = envRec;
            env.Outer             = F.Environment;
            return(env);
        }
 public FunctionEnvironmentRecord(FunctionObject F, IValue newTarget)
 {
     FunctionObject = F;
     if (F.ThisMode == ThisMode.Lexical)
     {
         ThisBindingStatus = ThisBindingStatus.Lexical;
     }
     else
     {
         ThisBindingStatus = ThisBindingStatus.Uninitialized;
     }
     HomeObject = F.HomeObject ?? UndefinedValue.Instance;
     NewTarget  = newTarget;
 }
Пример #4
0
        public static FunctionObject FunctionInitialize(FunctionObject f, FunctionCreateKind kind, FormalParameters parameters, FunctionStatementList body, LexicalEnvironment scope)
        {
            var len = parameters.ExpectedArgumentCount();

            f.DefinePropertyOrThrow("length", new PropertyDescriptor(new NumberValue(len), false, false, true));
            f.Environment      = scope;
            f.FormalParameters = parameters;
            f.Code             = body;
            if (kind == FunctionCreateKind.Arrow)
            {
                f.ThisMode = ThisMode.Lexical;
            }
            else if (f.Strict)
            {
                f.ThisMode = ThisMode.Strict;
            }
            else
            {
                f.ThisMode = ThisMode.Global;
            }
            return(f);
        }
Пример #5
0
        public static FunctionObject FunctionAllocate(IValue prototype, bool strict, FunctionKind functionKind)
        {
            if (!(prototype is Object))
            {
                throw new InvalidOperationException("FunctionObject.FunctionAllocate: non-object prototype is not allowed.");
            }
            bool needsConstruct = functionKind == FunctionKind.Normal;

            if (functionKind == FunctionKind.NonConstructor)
            {
                functionKind = FunctionKind.Normal;
            }
            var F = new FunctionObject();

            if (needsConstruct)
            {
                F.ConstructorKind = ConstructorKind.Base;
            }
            F.Strict       = strict;
            F.FunctionKind = functionKind;
            F.SetPrototypeOf(prototype);
            F.Realm = Interpreter.Instance().RunningExecutionContext().Realm;
            return(F);
        }
Пример #6
0
        public Completion FunctionDeclarationInstantiation(IReadOnlyList <IValue> arguments)
        {
            var calleeContext           = Interpreter.Instance().RunningExecutionContext();
            var env                     = calleeContext.LexicalEnvironment;
            var envRec                  = env.EnvironmentRecord;
            var parameterNames          = FormalParameters.BoundNames();
            var hasDuplicates           = parameterNames.Distinct().Count() < parameterNames.Count;
            var simpleParameterList     = FormalParameters.IsSimpleParameterList();
            var hasParameterExpressions = FormalParameters.formalParameters.Any(p => p.hasInitializer);
            var varNames                = Code.VarDeclaredNames();
            var varDeclarations         = Code.VarScopedDeclarations();
            var functionNames           = new LinkedList <string>();
            var functionsToInitialize   = new LinkedList <FunctionDeclaration>();

            foreach (var d in varDeclarations.Reverse())
            {
                if (d is FunctionDeclaration functionDeclaration)
                {
                    var fn = functionDeclaration.BoundNames()[0];
                    if (!functionNames.Contains(fn))
                    {
                        functionNames.AddFirst(fn);
                        functionsToInitialize.AddFirst(functionDeclaration);
                    }
                }
            }
            var argumentsObjectNeeded = true;

            if (ThisMode == ThisMode.Lexical)
            {
                argumentsObjectNeeded = false;
            }
            else if (parameterNames.Contains("arguments"))
            {
                argumentsObjectNeeded = false;
            }
            else if (!hasParameterExpressions)
            {
                if (functionNames.Contains("arguments"))
                {
                    argumentsObjectNeeded = false;
                }
            }
            foreach (var paramName in parameterNames)
            {
                var alreadyDeclared = envRec.HasBinding(paramName).Other == true;
                if (!alreadyDeclared)
                {
                    envRec.CreateMutableBinding(paramName, false);
                    if (hasDuplicates)
                    {
                        envRec.InitializeBinding(paramName, UndefinedValue.Instance);
                    }
                }
            }
            IReadOnlyList <string> parameterBindings;

            if (argumentsObjectNeeded)
            {
                Object ao;
                if (Strict || !simpleParameterList)
                {
                    ao = CreateUnmappedArgumentsObject(arguments);
                }
                else
                {
                    ao = CreateMappedArgumentsObject(FormalParameters, arguments, envRec);
                }
                if (Strict)
                {
                    envRec.CreateImmutableBinding("arguments", false);
                }
                else
                {
                    envRec.CreateMutableBinding("arguments", false);
                }
                envRec.InitializeBinding("arguments", ao);
                parameterBindings = parameterNames.Concat(new[] { "arguments" }).ToList();
            }
            else
            {
                parameterBindings = parameterNames;
            }
            var        iterator = new ArgumentIterator(arguments);
            Completion comp;

            if (hasDuplicates)
            {
                comp = FormalParameters.IteratorBindingInitialization(null, iterator);
            }
            else
            {
                comp = FormalParameters.IteratorBindingInitialization(env, iterator);
            }
            if (comp.IsAbrupt())
            {
                return(comp);
            }

            LexicalEnvironment varEnv;
            EnvironmentRecord  varEnvRec;

            if (!hasParameterExpressions)
            {
                var instantiatedVarNames = new List <string>(parameterNames);
                foreach (var n in varNames)
                {
                    if (!instantiatedVarNames.Contains(n))
                    {
                        instantiatedVarNames.Add(n);
                        envRec.CreateMutableBinding(n, false);
                        envRec.InitializeBinding(n, UndefinedValue.Instance);
                    }
                }
                varEnv    = env;
                varEnvRec = envRec;
            }
            else
            {
                varEnv    = env.NewDeclarativeEnvironment();
                varEnvRec = varEnv.EnvironmentRecord;
                calleeContext.VariableEnvironment = varEnv;
                var instantiatedVarNames = new List <string>();
                foreach (var n in varNames)
                {
                    if (!instantiatedVarNames.Contains(n))
                    {
                        instantiatedVarNames.Add(n);
                        varEnvRec.CreateMutableBinding(n, false);
                        IValue initialValue;
                        if (!parameterBindings.Contains(n) || functionNames.Contains(n))
                        {
                            initialValue = UndefinedValue.Instance;
                        }
                        else
                        {
                            initialValue = envRec.GetBindingValue(n, false).value !;
                        }
                        varEnvRec.InitializeBinding(n, initialValue);
                    }
                }
            }
            var lexEnv = !Strict?varEnv.NewDeclarativeEnvironment() : varEnv;

            var lexEnvRec = lexEnv.EnvironmentRecord;

            calleeContext.LexicalEnvironment = lexEnv;
            var lexDeclarations = Code.LexicallyScopedDeclarations();

            foreach (var d in lexDeclarations)
            {
                foreach (var dn in d.BoundNames())
                {
                    if (d.IsConstantDeclaration())
                    {
                        lexEnvRec.CreateImmutableBinding(dn, true);
                    }
                    else
                    {
                        lexEnvRec.CreateMutableBinding(dn, false);
                    }
                }
            }
            foreach (var f in functionsToInitialize)
            {
                var            fn = f.BoundNames()[0];
                FunctionObject fo = f.InstantiateFunctionObject(lexEnv);
                varEnvRec.SetMutableBinding(fn, fo, false);
            }

            return(Completion.NormalCompletion());
        }
Пример #7
0
        private Completion CreateDynamicFunction(Object?newTarget, FunctionKind kind, IReadOnlyList <IValue> arguments)
        {
            if (Interpreter.Instance().ExecutionContextStackSize() < 2)
            {
                throw new InvalidOperationException("Spec 19.2.1.1.1 step 1");
            }
            var callerContext = Interpreter.Instance().SecondExecutionContext();
            var callerRealm   = callerContext.Realm;
            var calleeRealm   = Interpreter.Instance().CurrentRealm();

            //TODO HostEnsureCanCompileStrings
            if (newTarget == null)
            {
                newTarget = this;
            }
            Func <Parser.Parser, AST.FunctionStatementList> goal;
            Func <Intrinsics, Object> fallbackProto;

            switch (kind)
            {
            case FunctionKind.Normal:
                goal          = (p) => p.ParseFunctionBody();
                fallbackProto = i => i.FunctionPrototype;
                break;

            default:
                throw new NotImplementedException("Async and/or generators");
            }
            var    argCount = arguments.Count;
            var    P        = "";
            string bodyText;

            if (argCount == 0)
            {
                bodyText = "";
            }
            else if (argCount == 1)
            {
                var bodyComp = arguments[0].ToJsString();
                if (bodyComp.IsAbrupt())
                {
                    return(bodyComp);
                }
                bodyText = (bodyComp.value as StringValue) !.@string;
            }
            else
            {
                var firstArg = arguments[0];
                var pComp    = firstArg.ToJsString();
                if (pComp.IsAbrupt())
                {
                    return(pComp);
                }
                P = (pComp.value as StringValue) !.@string;
                int k = 1;
                for (; k < argCount - 1; k++)
                {
                    var nextArg           = arguments[k];
                    var nextArgStringComp = nextArg.ToJsString();
                    if (nextArgStringComp.IsAbrupt())
                    {
                        return(nextArgStringComp);
                    }
                    var nextArgString = (nextArgStringComp.value as StringValue) !.@string;
                    P += "," + nextArgString;
                }
                var bodyComp = arguments[k].ToJsString();
                if (bodyComp.IsAbrupt())
                {
                    return(bodyComp);
                }
                bodyText = (bodyComp.value as StringValue) !.@string;
            }
            AST.FormalParameters?parameters = new AST.FormalParameters();
            try
            {
                if (!string.IsNullOrEmpty(P))
                {
                    parameters = new Parser.Parser(P).ParseFormalParameters();
                }
                if (parameters == null)
                {
                    throw new Parser.ParseFailureException($"parameters {P} could not be parsed.");
                }
            }
            catch (Parser.ParseFailureException e)
            {
                return(Completion.ThrowSyntaxError($"Failed to parse parameters \"{P}\".\n{e.Message}"));
            }
            AST.FunctionStatementList body;
            try
            {
                body = goal(new Parser.Parser(bodyText));
            }
            catch (Parser.ParseFailureException e)
            {
                return(Completion.ThrowSyntaxError($"Failed to parse body \"{bodyText}\".\n{e.Message}"));
            }
            //TODO detect strict mode: ContainsUseStrict
            bool strict = body.IsStrictMode;

            if (!parameters.IsSimpleParameterList() && strict)
            {
                return(Completion.ThrowSyntaxError($"parameters must be simple in strict mode. \"{P}\""));
            }
            //TODO implement tree walking for checking if parameters or body contains a SuperCall or SuperProperty
            //TODO generator yield, async await errors
            var protoComp = Utils.GetPrototypeFromConstructor(newTarget, fallbackProto);

            if (protoComp.IsAbrupt())
            {
                return(protoComp);
            }
            var proto  = protoComp.value;
            var F      = FunctionObject.FunctionAllocate(proto !, strict, kind);
            var realmF = F.Realm;
            var scope  = realmF.GlobalEnv;

            FunctionObject.FunctionInitialize(F, FunctionCreateKind.Normal, parameters, body, scope);
            //TODO generator, async generator
            if (kind == FunctionKind.Normal)
            {
                F.MakeConstructor();
            }
            F.SetFunctionName("anonymous");
            return(Completion.NormalCompletion(F));
        }