示例#1
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());
        }