Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[dotnet] Instantiate protos in inner routines to create dispatch rout…

…ines with the candidate list for that block. We actually do this by copying the most immediately outer instantiation's candidate list and then adding the new ones to the list, which seems likely-ish to get closure semantics right while giving the semantics as per spec. It's very much an instantiation in that it shares body and other bits with the original proto, though.
  • Loading branch information...
commit aa4bd8523af9891702eb8989869184977102752c 1 parent 0d78282
Jonathan Worthington authored October 30, 2010
48  dotnet/compiler/Actions.pm
@@ -503,29 +503,55 @@ method routine_def($/) {
503 503
                 # Otherwise, no candidate holder, so add one.
504 504
                 else {
505 505
                     # Check we have a proto in scope.
506  
-                    # XXX We need to get the proto clone from outer in place
507  
-                    # but for now just handle it being in the same block.
508  
-                    unless %sym<proto> {
509  
-                        $/.CURSOR.panic("Sorry, can only declare multis in the same block as a proto so far");
  506
+                    if %sym<proto> {
  507
+                        # WTF, a proto is in this scope, but didn't set up a
  508
+                        # candidate holder?!
  509
+                        $/.CURSOR.panic('Internal Error: Current scope has a proto, but no candidate list holder was set up. (This should never happen.)');
  510
+                    }
  511
+                    my $found_proto;
  512
+                    for @BLOCK {
  513
+                        my %sym := $_.symbol($name);
  514
+                        if %sym<proto> || %sym<cholder> {
  515
+                            $found_proto := 1;
  516
+                        }
  517
+                        elsif %sym {
  518
+                            $/.CURSOR.panic("Cannot declare a multi when an only is already in scope.");
  519
+                        }
  520
+                    }
  521
+
  522
+                    # If we didn't find a proto, error for now.
  523
+                    unless $found_proto {
  524
+                        $/.CURSOR.panic("Sorry, no proto sub in scope, and auto-generation of protos is not yet implemented.");
510 525
                     }
511 526
 
512  
-                    # Valid to add a candidate holder, so do so.
  527
+                    # Set up dispatch routine in this scope.
513 528
                     $cholder := PAST::Op.new( :pasttype('list') );
514  
-                    @BLOCK[0][0].push(PAST::Op.new(
515  
-                        :pasttype('nqpop'), :name('set_dispatchees'),
516  
-                        PAST::Var.new( :name($name) ),
  529
+                    my $dispatch_setup := PAST::Op.new(
  530
+                        :pasttype('nqpop'), :name('create_dispatch_and_add_candidates'),
  531
+                        PAST::Var.new( :name($name), :scope('outer') ),
517 532
                         $cholder
518  
-                    ));
519  
-                    @BLOCK[0].symbol($name, :cholder($cholder));
  533
+                    );
  534
+                    @BLOCK[0][0].push(PAST::Var.new( :name($name), :isdecl(1),
  535
+                                      :viviself($dispatch_setup), :scope('lexical') ) );
  536
+                    @BLOCK[0].symbol($name, :scope('lexical'), :cholder($cholder) );
520 537
                 }
521 538
 
522 539
                 # Add this candidate to the holder.
523 540
                 $cholder.push($past);
524 541
             }
525 542
             elsif $*MULTINESS eq 'proto' {
  543
+                # Create a candidate list holder for the dispatchees
  544
+                # this proto will work over, and install them along
  545
+                # with the proto.
  546
+                my $cholder := PAST::Op.new( :pasttype('list') );
526 547
                 @BLOCK[0][0].push(PAST::Var.new( :name($name), :isdecl(1),
527 548
                                       :viviself($past), :scope('lexical') ) );
528  
-                @BLOCK[0].symbol($name, :scope('lexical'), :proto(1) );
  549
+                @BLOCK[0][0].push(PAST::Op.new(
  550
+                    :pasttype('nqpop'), :name('set_dispatchees'),
  551
+                    PAST::Var.new( :name($name) ),
  552
+                    $cholder
  553
+                ));
  554
+                @BLOCK[0].symbol($name, :scope('lexical'), :proto(1), :cholder($cholder) );
529 555
             }
530 556
             else {
531 557
                 @BLOCK[0][0].push(PAST::Var.new( :name($name), :isdecl(1),
44  dotnet/runtime/Runtime/Ops.cs
@@ -581,6 +581,50 @@ public static RakudoObject set_dispatchees(ThreadContext TC, RakudoObject CodeOb
581 581
         }
582 582
 
583 583
         /// <summary>
  584
+        /// Creates an instantiation of the dispatch routine (or proto, which may
  585
+        /// serve as one) supplied and augments it with the provided candidates.
  586
+        /// It relies on being passed the instantiation of the dispatcher from the
  587
+        /// last outer scope that had an instantiation, and we thus take its
  588
+        /// candidates. This may or may not hold up in the long run; it works out
  589
+        /// in the Perl 6-y "you can make a new instance from any object" sense
  590
+        /// though, and seems more likely to get the closure semantics right than
  591
+        /// any of the other approaches I've considered so far.
  592
+        /// </summary>
  593
+        /// <param name="TC"></param>
  594
+        /// <param name="ToInstantiate"></param>
  595
+        /// <param name="ExtraDispatchees"></param>
  596
+        /// <returns></returns>
  597
+        public static RakudoObject create_dispatch_and_add_candidates(ThreadContext TC, RakudoObject ToInstantiate, RakudoObject ExtraDispatchees)
  598
+        {
  599
+            // Make sure we got the right things.
  600
+            var Source = ToInstantiate as RakudoCodeRef.Instance;
  601
+            var AdditionalDispatchList = ExtraDispatchees as P6list.Instance;
  602
+            if (Source == null || AdditionalDispatchList == null)
  603
+                throw new Exception("create_dispatch_and_add_candidates expects a RakudoCodeRef and a P6list");
  604
+
  605
+            // Clone all but SC (since it's a new object and doesn't live in any
  606
+            // SC yet) and dispatchees (which we want to munge).
  607
+            var NewDispatch = new RakudoCodeRef.Instance(Source.STable);
  608
+            NewDispatch.Body = Source.Body;
  609
+            NewDispatch.CurrentContext = Source.CurrentContext;
  610
+            NewDispatch.Handlers = Source.Handlers;
  611
+            NewDispatch.OuterBlock = Source.OuterBlock;
  612
+            NewDispatch.OuterForNextInvocation = Source.OuterForNextInvocation;
  613
+            NewDispatch.Sig = Source.Sig;
  614
+            NewDispatch.StaticLexPad = Source.StaticLexPad;
  615
+
  616
+            // Take existing candidates and add new ones.
  617
+            NewDispatch.Dispatchees = new RakudoObject[Source.Dispatchees.Length + AdditionalDispatchList.Storage.Count];
  618
+            var i = 0;
  619
+            for (int j = 0; j < Source.Dispatchees.Length; j++)
  620
+                NewDispatch.Dispatchees[i++] = Source.Dispatchees[j];
  621
+            for (int j = 0; j < AdditionalDispatchList.Storage.Count; j++)
  622
+                NewDispatch.Dispatchees[i++] = AdditionalDispatchList.Storage[j];
  623
+
  624
+            return NewDispatch;
  625
+        }
  626
+
  627
+        /// <summary>
584 628
         /// Gets a value at a given positional index from a low level list
585 629
         /// (something that uses the P6list representation).
586 630
         /// </summary>

0 notes on commit aa4bd85

Please sign in to comment.
Something went wrong with that request. Please try again.