diff --git a/dotnet/compiler/Actions.pm b/dotnet/compiler/Actions.pm index b99bde6..0473602 100644 --- a/dotnet/compiler/Actions.pm +++ b/dotnet/compiler/Actions.pm @@ -458,28 +458,45 @@ method routine_def($/) { $past.name($name); if $*SCOPE eq '' || $*SCOPE eq 'my' { if $*MULTINESS eq 'multi' { - # Find the proto. - my $found := 0; - for @BLOCK { - my %sym := $_.symbol($name); - if %sym { - if %sym { - @BLOCK[0][0].push(PAST::Op.new( - :pasttype('callmethod'), :name('!add_dispatchee'), - PAST::Var.new( :name($name) ), - $past - )); - $found := 1; - last; - } - else { - $/.CURSOR.panic("multi cannot be declared when only in scope"); + my $chname := '!' ~ $name ~ '-candidates'; + my $cholder; + # Does the current block have a candidate holder in place? + my %sym := @BLOCK[0].symbol($chname); + if %sym { + $cholder := %sym; + } + + # Otherwise, no candidate holder, so add one. + else { + # Check we have a proto in scope. + my $found := 0; + for @BLOCK { + my %sym := $_.symbol($name); + if %sym { + if %sym { + $found := 1; + last; + } + else { + $/.CURSOR.panic("multi cannot be declared when only in scope"); + } } } + unless $found { + $/.CURSOR.panic("multi cannot be declared without a proto in scope"); + } + + # Valid to add a candidate holder, so do so. + $cholder := PAST::Op.new( + :pasttype('call'), :name('&list'), + ); + @BLOCK[0][0].push(PAST::Var.new( :name($chname), :isdecl(1), + :viviself($cholder), :scope('lexical') ) ); + @BLOCK[0].symbol($chname, :cholder($cholder) ); } - unless $found { - $/.CURSOR.panic("multi cannot be declared without a proto in scope"); - } + + # Add this candidate to the holder. + $cholder.push($past); } else { @BLOCK[0][0].push(PAST::Var.new( :name($name), :isdecl(1), diff --git a/dotnet/runtime/Init.cs b/dotnet/runtime/Init.cs index 7e5a2f3..d08b2da 100644 --- a/dotnet/runtime/Init.cs +++ b/dotnet/runtime/Init.cs @@ -55,9 +55,6 @@ public static ThreadContext Initialize(string SettingName) Thread.DefaultNumBoxType = SettingContext.LexPad["NQPNum"]; Thread.DefaultStrBoxType = SettingContext.LexPad["NQPStr"]; - // LLCode type object should get a HOW. - SetupLLCodeHOW(Thread, (RakudoCodeRef.Instance)SettingContext.LexPad["LLCode"]); - return Thread; } @@ -80,30 +77,6 @@ private static void RegisterRepresentations() } } - /// - /// Adds to the low level code object's HOW. - /// - /// - /// - private static void SetupLLCodeHOW(ThreadContext TC, RakudoCodeRef.Instance LLCode) - { - var HOW = LLCode.STable.HOW; - var Meth = HOW.STable.FindMethod(TC, HOW, "add_method", Hints.NO_HINT); - Meth.STable.Invoke(TC, Meth, CaptureHelper.FormWith(new RakudoObject[] { - HOW, LLCode, - Runtime.Ops.box_str(TC, "!add_dispatchee", TC.DefaultStrBoxType), - CodeObjectUtility.WrapNativeMethod((TC_unused, self, c) => - { - var Instance = CaptureHelper.GetPositional(c, 0) as RakudoCodeRef.Instance; - var Dispatchee = CaptureHelper.GetPositional(c, 1) as RakudoCodeRef.Instance; - if (Instance.Dispatchees == null) - Instance.Dispatchees = new List(); - Instance.Dispatchees.Add(Dispatchee); - return CaptureHelper.Nil(); - }) - })); - } - /// /// Sets up the bootstrapping setting that we use to compile the /// real setting. diff --git a/dotnet/runtime/Metamodel/Representations/RakudoCodeRef.cs b/dotnet/runtime/Metamodel/Representations/RakudoCodeRef.cs index eb471b5..16b7348 100644 --- a/dotnet/runtime/Metamodel/Representations/RakudoCodeRef.cs +++ b/dotnet/runtime/Metamodel/Representations/RakudoCodeRef.cs @@ -43,11 +43,6 @@ public sealed class Instance : RakudoObject /// public Context CurrentContext; - /// - /// Things we have control over the dispatch of. - /// - public List Dispatchees; - public Instance(SharedTable STable) { this.STable = STable; diff --git a/dotnet/runtime/Rakudo.Net.csproj b/dotnet/runtime/Rakudo.Net.csproj index 19b57f8..848a99c 100644 --- a/dotnet/runtime/Rakudo.Net.csproj +++ b/dotnet/runtime/Rakudo.Net.csproj @@ -72,6 +72,8 @@ + + diff --git a/dotnet/runtime/Runtime/MultiDispatch/LexicalCandidateFinder.cs b/dotnet/runtime/Runtime/MultiDispatch/LexicalCandidateFinder.cs new file mode 100644 index 0000000..17706dd --- /dev/null +++ b/dotnet/runtime/Runtime/MultiDispatch/LexicalCandidateFinder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Rakudo.Metamodel; +using Rakudo.Metamodel.Representations; + +namespace Rakudo.Runtime.MultiDispatch +{ + /// + /// Finds all candidates that we may dispatch to. + /// + public static class LexicalCandidateFinder + { + /// + /// Locates all matching candidates between the two scopes. + /// + /// + /// + /// + /// + public static List FindCandidates(Context CallerScope, Context ProtoScope, string CandidateHolderName) + { + var Result = new List(); + Context CurScope = null; + do + { + // Get the next outer scope, or alternatively start off with the + // caller scope. + CurScope = CurScope == null ? CallerScope : CurScope.Outer; + + // Any candidates here? + + + } while (CurScope != ProtoScope); + return Result; + } + } +} diff --git a/dotnet/runtime/Runtime/MultiDispatch/MultiDispatcher.cs b/dotnet/runtime/Runtime/MultiDispatch/MultiDispatcher.cs new file mode 100644 index 0000000..d5e2966 --- /dev/null +++ b/dotnet/runtime/Runtime/MultiDispatch/MultiDispatcher.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Rakudo.Metamodel; +using Rakudo.Metamodel.Representations; + +namespace Rakudo.Runtime.MultiDispatch +{ + /// + /// Very first cut implementation of a multi-dispatcher. Doesn't yet + /// know about subtyping beyond no type being the top type. Yes, this + /// will likely get replaced (or extensively re-done) at some point. + /// + public static class MultiDispatcher + { + public static RakudoCodeRef.Instance FindBestCandidate(List Candidates, RakudoObject Capture) + { + throw new NotImplementedException(); + } + } +} diff --git a/dotnet/runtime/Runtime/Ops.cs b/dotnet/runtime/Runtime/Ops.cs index 4437cd1..40bf1e9 100644 --- a/dotnet/runtime/Runtime/Ops.cs +++ b/dotnet/runtime/Runtime/Ops.cs @@ -469,5 +469,22 @@ public static RakudoObject concat(ThreadContext TC, RakudoObject x, RakudoObject { return Ops.box_str(TC, Ops.unbox_str(TC, x) + Ops.unbox_str(TC, y), TC.DefaultStrBoxType); } + + /// + /// Entry point to multi-dispatch over the candidates in the inner + /// dispatcher. + /// + /// + /// + public static RakudoObject multi_dispatch_over_lexical_candidates(ThreadContext TC, RakudoObject Name) + { + var Candidate = MultiDispatch.MultiDispatcher.FindBestCandidate( + MultiDispatch.LexicalCandidateFinder.FindCandidates( + TC.CurrentContext.Caller, + TC.CurrentContext, + "!" + Ops.unbox_str(TC, Name) + "-candidates"), + TC.CurrentContext.Capture); + return Candidate.STable.Invoke(TC, Candidate, TC.CurrentContext.Capture); + } } }