Instance that uses the RakudoCodeRef representation.
Inheritance: RakudoObject
Exemple #1
0
        /// <summary>
        /// Creates an instantiation of the dispatch routine (or proto, which may
        /// serve as one) supplied and augments it with the provided candidates.
        /// It relies on being passed the instantiation of the dispatcher from the
        /// last outer scope that had an instantiation, and we thus take its
        /// candidates. This may or may not hold up in the long run; it works out
        /// in the Perl 6-y "you can make a new instance from any object" sense
        /// though, and seems more likely to get the closure semantics right than
        /// any of the other approaches I've considered so far.
        /// </summary>
        /// <param name="TC"></param>
        /// <param name="ToInstantiate"></param>
        /// <param name="ExtraDispatchees"></param>
        /// <returns></returns>
        public static RakudoObject create_dispatch_and_add_candidates(ThreadContext TC, RakudoObject ToInstantiate, RakudoObject ExtraDispatchees)
        {
            // Make sure we got the right things.
            var Source = ToInstantiate as RakudoCodeRef.Instance;
            var AdditionalDispatchList = ExtraDispatchees as P6list.Instance;
            if (Source == null || AdditionalDispatchList == null)
                throw new Exception("create_dispatch_and_add_candidates expects a RakudoCodeRef and a P6list");

            // Clone all but SC (since it's a new object and doesn't live in any
            // SC yet) and dispatchees (which we want to munge).
            var NewDispatch = new RakudoCodeRef.Instance(Source.STable);
            NewDispatch.Body = Source.Body;
            NewDispatch.CurrentContext = Source.CurrentContext;
            NewDispatch.Handlers = Source.Handlers;
            NewDispatch.OuterBlock = Source.OuterBlock;
            NewDispatch.OuterForNextInvocation = Source.OuterForNextInvocation;
            NewDispatch.Sig = Source.Sig;
            NewDispatch.StaticLexPad = Source.StaticLexPad;

            // Take existing candidates and add new ones.
            NewDispatch.Dispatchees = new RakudoObject[Source.Dispatchees.Length + AdditionalDispatchList.Storage.Count];
            var i = 0;
            for (int j = 0; j < Source.Dispatchees.Length; j++)
                NewDispatch.Dispatchees[i++] = Source.Dispatchees[j];
            for (int j = 0; j < AdditionalDispatchList.Storage.Count; j++)
                NewDispatch.Dispatchees[i++] = AdditionalDispatchList.Storage[j];

            return NewDispatch;
        }
Exemple #2
0
        /// <summary>
        /// Initializes the context.
        /// </summary>
        /// <param name="StaticCodeObject"></param>
        /// <param name="Caller"></param>
        public Context(RakudoObject StaticCodeObject_Uncast, Context Caller, RakudoObject Capture)
        {
            // Set up static code object and caller pointers.
            var StaticCodeObject = (RakudoCodeRef.Instance)StaticCodeObject_Uncast;
            this.StaticCodeObject = StaticCodeObject;
            this.Caller = Caller;
            this.Capture = Capture;

            // Static sub object should have this as the current
            // context.
            StaticCodeObject.CurrentContext = this;

            // Lex pad should be an "instantiation" of the static one.
            // Instantiating a lexpad creates a new dynamic instance of it
            // from a static one, copying over the slot storage entries
            // from the static one but sharing the slot mapping.
            this.LexPad.SlotMapping = StaticCodeObject.StaticLexPad.SlotMapping;
            this.LexPad.Storage = (RakudoObject[])StaticCodeObject.StaticLexPad.Storage.Clone();

            // Set outer context.
            if (StaticCodeObject.OuterForNextInvocation != null)
            {
                this.Outer = StaticCodeObject.OuterForNextInvocation;
            }
            else if (StaticCodeObject.OuterBlock.CurrentContext != null)
            {
                this.Outer = StaticCodeObject.OuterBlock.CurrentContext;
            }
            else
            {
                // Auto-close. In this we go setting up fake contexts
                // that use the static lexpad until we find a real one.
                var CurContext = this;
                var OuterBlock = StaticCodeObject.OuterBlock;
                while (OuterBlock != null)
                {
                    // If we found a block with a context, we're done.
                    if (OuterBlock.CurrentContext != null)
                    {
                        CurContext.Outer = OuterBlock.CurrentContext;
                        break;
                    }

                    // Build the fake context.
                    var OuterContext = new Context();
                    OuterContext.StaticCodeObject = OuterBlock;
                    OuterContext.LexPad = OuterBlock.StaticLexPad;

                    // Link it.
                    CurContext.Outer = OuterContext;

                    // Step back one level.
                    CurContext = OuterContext;
                    OuterBlock = OuterBlock.OuterBlock;
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Creates a clone of the given code object, and makes its outer context
        /// be set to the current context.
        /// </summary>
        /// <param name="TC"></param>
        /// <param name="Block"></param>
        /// <returns></returns>
        public static RakudoObject new_closure(ThreadContext TC, RakudoCodeRef.Instance Block)
        {
            // Clone all but OuterForNextInvocation and SC (since it's a new
            // object and doesn't live in any SC yet).
            var NewBlock = new RakudoCodeRef.Instance(Block.STable);
            NewBlock.Body = Block.Body;
            NewBlock.CurrentContext = Block.CurrentContext;
            NewBlock.Dispatchees = Block.Dispatchees;
            NewBlock.Handlers = Block.Handlers;
            NewBlock.OuterBlock = Block.OuterBlock;
            NewBlock.Sig = Block.Sig;
            NewBlock.StaticLexPad = Block.StaticLexPad;

            // Set the outer for next invocation and return the cloned block.
            NewBlock.OuterForNextInvocation = TC.CurrentContext;
            return NewBlock;
        }
 /// <summary>
 /// Creates a LeaveStackUnwinderException to target the given block
 /// and exit it with the specified payload.
 /// </summary>
 /// <param name="TargetBlock"></param>
 /// <param name="PayLoad"></param>
 public LeaveStackUnwinderException(RakudoCodeRef.Instance TargetBlock, RakudoObject PayLoad)
 {
     this.TargetBlock = TargetBlock;
     this.PayLoad = PayLoad;
 }
Exemple #5
0
        /// <summary>
        /// Sorts the candidates.
        /// </summary>
        /// <param name="Unsorted"></param>
        /// <returns></returns>
        private static RakudoCodeRef.Instance[] Sort(ThreadContext TC, RakudoObject[] Unsorted)
        {
            /* Allocate results array (just allocate it for worst case, which
             * is no ties ever, so a null between all of them, and then space
             * for the terminating null. */
            var NumCandidates = Unsorted.Length;
            var Result = new RakudoCodeRef.Instance[2 * NumCandidates + 1];

            /* Create a node for each candidate in the graph. */
            var Graph = new CandidateGraphNode[NumCandidates];
            for (int i = 0; i < NumCandidates; i++)
            {
                Graph[i] = new CandidateGraphNode()
                {
                    Candidate = (RakudoCodeRef.Instance)Unsorted[i],
                    Edges = new CandidateGraphNode[NumCandidates]
                };
            }

            /* Now analyze type narrowness of the candidates relative to each other
             * and create the edges. */
            for (int i = 0; i < NumCandidates; i++) {
                for (int j = 0; j < NumCandidates; j++) {
                    if (i == j)
                        continue;
                    if (IsNarrower(TC, Graph[i].Candidate, Graph[j].Candidate) != 0) {
                        Graph[i].Edges[Graph[i].EdgesOut] = Graph[j];
                        Graph[i].EdgesOut++;
                        Graph[j].EdgesIn++;
                    }
                }
            }

            /* Perform the topological sort. */
            int CandidatesToSort = NumCandidates;
            int ResultPos = 0;
            while (CandidatesToSort > 0)
            {
                int StartPoint = ResultPos;

                /* Find any nodes that have no incoming edges and add them to
                 * results. */
                for (int i = 0; i < NumCandidates; i++) {
                    if (Graph[i].EdgesIn == 0) {
                        /* Add to results. */
                        Result[ResultPos] = Graph[i].Candidate;
                        Graph[i].Candidate = null;
                        ResultPos++;
                        CandidatesToSort--;
                        Graph[i].EdgesIn = EDGE_REMOVAL_TODO;
                    }
                }
                if (StartPoint == ResultPos) {
                    throw new Exception("Circularity detected in multi sub types.");
                }

                /* Now we need to decrement edges in counts for things that had
                 * edges from candidates we added here. */
                for (int i = 0; i < NumCandidates; i++) {
                    if (Graph[i].EdgesIn == EDGE_REMOVAL_TODO) {
                        for (int j = 0; j < Graph[i].EdgesOut; j++)
                            Graph[i].Edges[j].EdgesIn--;
                        Graph[i].EdgesIn = EDGE_REMOVED;
                    }
                }

                /* This is end of a tied group, so leave a gap. */
                ResultPos++;
            }

            return Result;
        }