Пример #1
0
        ///////////////////////////////////////////////////////////////////////

        #region IExecute Members
        public override ReturnCode Execute(
            Interpreter interpreter,
            IClientData clientData,
            ArgumentList arguments,
            ref Result result
            )
        {
            ReturnCode code = ReturnCode.Ok;

            if (interpreter != null)
            {
                if (arguments != null)
                {
                    IScriptLocation location = null;

                    code = ScriptOps.GetAndCheckProcedureLocation(
                        interpreter, this, ref location, ref result);

                    if (code == ReturnCode.Ok)
                    {
                        string       procedureName      = this.Name;
                        ArgumentList procedureArguments = this.Arguments;

                        if (procedureArguments != null)
                        {
                            bool hasArgs      = procedureArguments.IsVariadic(true);
                            int  totalArgs    = hasArgs ? procedureArguments.Count - 1 : procedureArguments.Count;
                            int  optionalArgs = procedureArguments.GetOptionalCount();

                            if ((arguments.Count > 0) &&
                                ((((arguments.Count - 1) >= (totalArgs - optionalArgs)) &&
                                  ((arguments.Count - 1) <= totalArgs)) ||
                                 (hasArgs && ((arguments.Count - 1) >= (totalArgs - optionalArgs)))))
                            {
                                ICallFrame frame = null;

                                try
                                {
                                    frame = interpreter.NewProcedureCallFrame(
                                        procedureName, CallFrameFlags.Procedure,
                                        null, this, arguments);

                                    VariableDictionary variables = frame.Variables;

                                    frame.ProcedureArguments = new ArgumentList(arguments[0]);

                                    for (int argumentIndex = 0; argumentIndex < procedureArguments.Count; argumentIndex++)
                                    {
                                        string varName = procedureArguments[argumentIndex].Name;

                                        if (!variables.ContainsKey(varName))
                                        {
                                            ArgumentFlags flags = ArgumentFlags.None;
                                            object        varValue;

                                            if (hasArgs && (argumentIndex == (procedureArguments.Count - 1)))
                                            {
                                                //
                                                // NOTE: This argument is part of an argument list.
                                                //
                                                flags |= ArgumentFlags.ArgumentList;

                                                //
                                                // NOTE: Build the list for the final formal argument value,
                                                //       which consists of all the remaining argument values.
                                                //
                                                ArgumentList argsArguments = new ArgumentList();

                                                for (int argsArgumentIndex = argumentIndex + 1;
                                                     argsArgumentIndex < arguments.Count; argsArgumentIndex++)
                                                {
                                                    //
                                                    // NOTE: Sync up the argument name and flags for use when
                                                    //       debugging (below).
                                                    //
                                                    Argument argsArgument = Argument.GetOrCreate(
                                                        interpreter, arguments[argsArgumentIndex].Flags | flags,
                                                        String.Format("{0}{1}{2}", varName, Characters.Space,
                                                                      argsArguments.Count), arguments[argsArgumentIndex],
                                                        interpreter.HasNoCacheArgument());

                                                    argsArguments.Add(argsArgument);
                                                }

                                                varValue = argsArguments;
                                            }
                                            else
                                            {
                                                if ((argumentIndex + 1) < arguments.Count)
                                                {
                                                    //
                                                    // NOTE: Sync up the argument name for use when
                                                    //       debugging (below) and use the value
                                                    //       supplied by the caller.
                                                    //
                                                    varValue = Argument.GetOrCreate(interpreter,
                                                                                    arguments[argumentIndex + 1].Flags | flags,
                                                                                    varName, arguments[argumentIndex + 1],
                                                                                    interpreter.HasNoCacheArgument());
                                                }
                                                else
                                                {
                                                    //
                                                    // NOTE: We cannot sync up the argument name here
                                                    //       because we are out-of-bounds on that list
                                                    //       and it cannot be extended (i.e. it would
                                                    //       break [info level]); therefore, we punt
                                                    //       on that for now.  Use the default value
                                                    //       for this argument, if any; otherwise, use
                                                    //       an empty string.
                                                    //
                                                    object @default = procedureArguments[argumentIndex].Default;
                                                    varValue = (@default != null) ? @default : Argument.NoValue;
                                                }
                                            }

                                            code = interpreter.SetVariableValue2(VariableFlags.Argument, frame,
                                                                                 varName, varValue, ref result);

                                            if (code != ReturnCode.Ok)
                                            {
                                                break;
                                            }

                                            //
                                            // BUGFIX: Now, also keep track of this argument in the procedure
                                            //         arguments list.  Primarily because we do not want to
                                            //         have to redo this logic later (i.e. for [scope]).
                                            //
                                            frame.ProcedureArguments.Add(Argument.GetOrCreate(
                                                                             interpreter, flags, varName, varValue,
                                                                             interpreter.HasNoCacheArgument()));
                                        }
                                    }

                                    //
                                    // NOTE: Make sure we succeeded in creating the call frame.
                                    //
                                    if (code == ReturnCode.Ok)
                                    {
                                        ICallFrame savedFrame = null;
                                        interpreter.PushProcedureCallFrame(frame, true, ref savedFrame);

                                        try
                                        {
#if DEBUGGER && DEBUGGER_EXECUTE
                                            if (DebuggerOps.CanHitBreakpoints(interpreter,
                                                                              EngineFlags.None, BreakpointType.BeforeProcedureBody))
                                            {
                                                code = interpreter.CheckBreakpoints(
                                                    code, BreakpointType.BeforeProcedureBody, procedureName,
                                                    null, null, this, null, clientData, arguments,
                                                    ref result);
                                            }
#endif

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool locked = false;

                                                try
                                                {
                                                    bool atomic = EntityOps.IsAtomic(this);

                                                    if (atomic)
                                                    {
                                                        interpreter.InternalTryLock(ref locked); /* TRANSACTIONAL */
                                                    }
                                                    if (!atomic || locked)
                                                    {
#if ARGUMENT_CACHE || PARSE_CACHE
                                                        EngineFlags savedEngineFlags = EngineFlags.None;
                                                        bool        nonCaching       = EntityOps.IsNonCaching(this);

                                                        if (nonCaching)
                                                        {
                                                            interpreter.BeginProcedureBodyNoCaching(
                                                                ref savedEngineFlags);
                                                        }

                                                        try
                                                        {
#endif
                                                        string body = this.Body;

                                                        interpreter.ReturnCode = ReturnCode.Ok;

                                                        code = interpreter.EvaluateScript(
                                                            body, location, ref result);
#if ARGUMENT_CACHE || PARSE_CACHE
                                                    }
                                                    finally
                                                    {
                                                        if (nonCaching)
                                                        {
                                                            interpreter.EndProcedureBodyNoCaching(
                                                                ref savedEngineFlags);
                                                        }
                                                    }
#endif
                                                    }
                                                    else
                                                    {
                                                        result = "could not lock interpreter";
                                                        code   = ReturnCode.Error;
                                                    }
                                                }
                                                finally
                                                {
                                                    interpreter.InternalExitLock(ref locked); /* TRANSACTIONAL */
                                                }

#if DEBUGGER && DEBUGGER_EXECUTE
                                                if (DebuggerOps.CanHitBreakpoints(interpreter,
                                                                                  EngineFlags.None, BreakpointType.AfterProcedureBody))
                                                {
                                                    code = interpreter.CheckBreakpoints(
                                                        code, BreakpointType.AfterProcedureBody, procedureName,
                                                        null, null, this, null, clientData, arguments,
                                                        ref result);
                                                }
#endif

                                                //
                                                // BUGFIX: If an opaque object handle is being returned, add
                                                //         a reference to it now.
                                                //
                                                if ((code == ReturnCode.Ok) || (code == ReturnCode.Return))
                                                {
                                                    code = interpreter.AddObjectReference(
                                                        code, result, ObjectReferenceType.Return,
                                                        ref result);
                                                }

                                                if (code == ReturnCode.Return)
                                                {
                                                    code = Engine.UpdateReturnInformation(interpreter);
                                                }
                                                else if (code == ReturnCode.Error)
                                                {
                                                    Engine.AddErrorInformation(interpreter, result,
                                                                               String.Format("{0}    (procedure \"{1}\" line {2})",
                                                                                             Environment.NewLine, FormatOps.Ellipsis(procedureName),
                                                                                             Interpreter.GetErrorLine(interpreter)));
                                                }
                                            }
                                        }
                                        finally
                                        {
                                            /* IGNORED */
                                            interpreter.PopProcedureCallFrame(frame, ref savedFrame);
                                        }
                                    }
                                }
                                finally
                                {
                                    if (frame != null)
                                    {
                                        IDisposable disposable = frame as IDisposable;

                                        if (disposable != null)
                                        {
                                            disposable.Dispose();
                                            disposable = null;
                                        }

                                        frame = null;
                                    }
                                }
                            }
                            else
                            {
                                if (procedureArguments.Count > 0)
                                {
                                    result = String.Format(
                                        "wrong # args: should be \"{0} {1}\"",
                                        Parser.Quote(procedureName),
                                        procedureArguments.ToRawString(ToStringFlags.Decorated,
                                                                       Characters.Space.ToString()));
                                }
                                else
                                {
                                    result = String.Format(
                                        "wrong # args: should be \"{0}\"",
                                        Parser.Quote(procedureName));
                                }

                                code = ReturnCode.Error;
                            }
                        }
                        else
                        {
                            result = "invalid procedure argument list";
                            code   = ReturnCode.Error;
                        }
                    }
                }
                else
                {
                    result = "invalid argument list";
                    code   = ReturnCode.Error;
                }
            }
            else
            {
                result = "invalid interpreter";
                code   = ReturnCode.Error;
            }

            return(code);
        }