예제 #1
0
        /// <summary>
        /// A subcontext carries the variable state of the parent FrameContext but runs different
        /// code with it. This is used for things like functions defined inside functions.
        /// </summary>
        /// <param name="subFrames">The frame stack to use for the subcontext.</param>
        /// <returns>A new FrameContext that has this FrameContext's variable state but the
        /// new callstack based on rootFrame.</returns>
        public FrameContext CreateSubcontext(Stack<Frame> subFrames)
        {
            Stack<Frame> reverseStack = new Stack<Frame>();
            foreach (var parentFrame in callStack)
            {
                reverseStack.Push(parentFrame);
            }
            foreach (var childFrame in subFrames)
            {
                reverseStack.Push(childFrame);
            }

            int subStartDepth = callStack.Count;
            FrameContext newContext = new FrameContext(reverseStack);
            newContext.StartDepth = subStartDepth;
            return newContext;
        }
예제 #2
0
 public void Prepare(IInterpreter interpreter, FrameContext context, IScheduler scheduler)
 {
     Interpreter = interpreter;
     Context     = context;
     Scheduler   = scheduler;
 }
예제 #3
0
 public Injector(IInterpreter interpreter, FrameContext context, IScheduler scheduler)
 {
     Prepare(interpreter, context, scheduler);
 }
예제 #4
0
 public WrappedCodeObject(FrameContext context, MethodBase[] methodBases)
 {
     this.MethodBases = methodBases;
     Name             = methodBases[0].Name;
     instance         = null;
 }
예제 #5
0
 public WrappedCodeObject(FrameContext context, string nameInsideInterpreter, MethodBase methodBase) : this(context, nameInsideInterpreter, new MethodBase[] { methodBase })
 {
     AssertMethodBaseNotNull(methodBase);
 }
예제 #6
0
 public WrappedCodeObject(FrameContext context, string nameInsideInterpreter, MethodBase[] methodBases)
 {
     this.MethodBases = methodBases;
     Name             = nameInsideInterpreter;
     instance         = null;
 }
예제 #7
0
 public WrappedCodeObject(FrameContext context, MethodBase methodBase, object instance) : this(context, new MethodBase[] { methodBase }, instance)
 {
     AssertMethodBaseNotNull(methodBase);
 }
예제 #8
0
 public WrappedCodeObject(FrameContext context, MethodBase[] methodBases, object instance)
 {
     this.MethodBases = methodBases;
     Name             = methodBases[0].Name;
     this.instance    = instance;
 }
예제 #9
0
        public Task <object> Call(IInterpreter interpreter, FrameContext context, object[] args)
        {
            var methodBase = findBestMethodMatch(args);

            // Strip generic arguments (if any).
            // Note this is kind of hacky! We get a monomorphized generic method back whether or not
            // we started out that way already. Current hack is to see if we have more arguments than
            // the method needs. If we do, then we strip the excess in front since they were used to
            // monomorphize the generic.
            int numGenerics            = 0;
            var noGenericArgs          = args;
            int actualParametersLength = methodBase.IsExtensionMethod() ? methodBase.GetParameters().Length - 1 : methodBase.GetParameters().Length;

            if ((methodBase.ContainsGenericParameters || methodBase.IsGenericMethod) && args.Length > actualParametersLength)
            {
                if (methodBase.IsConstructor)
                {
                    // If this is a constructor, then the class we're instantiating itself might be generic. The constructor
                    // can't legally define additional arguments, so the generic arguments boil down to what the type itself
                    // defines.
                    var asConstructor = methodBase as ConstructorInfo;
                    numGenerics = asConstructor.DeclaringType.GetGenericArguments().Length;
                }
                else
                {
                    numGenerics   = methodBase.GetGenericArguments().Length;
                    noGenericArgs = new object[args.Length - numGenerics];
                }
            }
            Array.Copy(args, numGenerics, noGenericArgs, 0, args.Length - numGenerics);

            // Inject internal types, convert .NET/Cloaca types.
            // Unit tests like to come in with a null interpreter so we have to test for it.
            var injector      = new Injector(interpreter, context, interpreter != null ? interpreter.Scheduler : null);
            var injected_args = injector.Inject(methodBase, noGenericArgs, instance);

            object[] final_args = injected_args;

            // Little convenience here. We'll convert a non-task Task<object> type to a task.
            var asMethodInfo = methodBase as MethodInfo;

            if (asMethodInfo != null && asMethodInfo.ReturnType.IsGenericType && asMethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task <>))
            {
                // Task<object> is straightforward and we can just return it. Other return types need to go through
                // our helper.
                if (asMethodInfo.ReturnType == typeof(Task <object>))
                {
                    return((Task <object>)methodBase.Invoke(instance, final_args));
                }
                else
                {
                    return(InvokeAsTaskObject(final_args));
                }
            }
            else
            {
                var asConstructor = methodBase as ConstructorInfo;
                if (asConstructor != null)
                {
                    // Special handling for generic constructors. The generic arguments for generic constructors are part of the type,
                    // not the constructor.
                    if (asConstructor.ContainsGenericParameters)
                    {
                        Type[] generics            = new Type[numGenerics];
                        var    constructorParamIns = methodBase.GetParameters();
                        Type[] constructorInTypes  = new Type[constructorParamIns.Length];
                        for (int param_i = 0; param_i < constructorInTypes.Length; ++param_i)
                        {
                            constructorInTypes[param_i] = constructorParamIns[param_i].ParameterType;
                        }
                        Array.Copy(args, 0, generics, 0, numGenerics);
                        Type monomorphedConstructor = asConstructor.DeclaringType.MakeGenericType(generics);
                        asConstructor = monomorphedConstructor.GetConstructor(constructorInTypes);
                    }
                    return(Task.FromResult(asConstructor.Invoke(final_args)));
                }
                else
                {
                    return(Task.FromResult(methodBase.Invoke(instance, final_args)));
                }
            }
        }
예제 #10
0
 public Task <object> Call(IInterpreter interpreter, FrameContext context, object[] args)
 {
     return(interpreter.CallInto(context, this, args));
 }
예제 #11
0
        public static Delegate Create(MethodInfo dotNetMethod, Type delegateType, IPyCallable callable, IInterpreter interpreter, FrameContext contextToUseForCall)
        {
            var proxy = new CallableDelegateProxy(callable, interpreter, contextToUseForCall);
            var dotNetMethodParamInfos = dotNetMethod.GetParameters();

            if (dotNetMethodParamInfos.Length > 2)
            {
                throw new NotImplementedException("We have only created templates for generic wrappers up to 4 arguments");
            }

            Delegate asDelegate;

            Type[]     delegateArgs;
            MethodInfo genericWrapper;

            // An ugly amount of copypasta. If we have a return type, then we need an array one element longer to put in RetVal at the end.
            // We also need to find the method matching the name of the right return type and accommodate the existing of a return value into
            // the number of generic parameters required for the right binding.
            if (dotNetMethod.ReturnType == typeof(void))
            {
                delegateArgs = new Type[dotNetMethodParamInfos.Length];
                for (int i = 0; i < dotNetMethodParamInfos.Length; ++i)
                {
                    delegateArgs[i] = dotNetMethodParamInfos[i].ParameterType;
                }
                genericWrapper = typeof(CallableDelegateProxy).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                                 .Where(x => x.Name == "GenericWrapperVoid" && x.GetParameters().Length == delegateArgs.Length)
                                 .First();
            }
            else
            {
                throw new Exception("Attempted to bind a callable to an event that requires a return type. We don't support this type of binding.  " +
                                    "All our callables have to be async, and that meddles with signature of basic return values. Why are you using an event with " +
                                    "a return type anyways?");
            }

            var monomorphizedWrapper = genericWrapper.MakeGenericMethod(delegateArgs);

            asDelegate = Delegate.CreateDelegate(delegateType, proxy, monomorphizedWrapper);
            return(asDelegate);
        }
예제 #12
0
 private CallableDelegateProxy(IPyCallable callable, IInterpreter interpreter, FrameContext contextToUseForCall)
 {
     this.callable            = callable;
     this.interpreter         = interpreter;
     this.contextToUseForCall = contextToUseForCall;
 }
예제 #13
0
 public ScheduledTaskRecord(FrameContext frame, ISubscheduledContinuation continuation, TaskEventRecord submitterReceipt)
 {
     Frame            = frame;
     Continuation     = continuation;
     SubmitterReceipt = submitterReceipt;
 }