Skip to content

Commit

Permalink
A fresh start at prototyping the new multi-dispatch, after discussion…
Browse files Browse the repository at this point in the history
…s with TimToady++. Nothing working yet, but this starts us storing the candidates per scope and stubs in some logic for us to go looking for them. Needs a first crack at lists before we can make this work at all, though.
  • Loading branch information
jnthn committed Aug 22, 2010
1 parent 98196e3 commit a389552
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 51 deletions.
55 changes: 36 additions & 19 deletions dotnet/compiler/Actions.pm
Expand Up @@ -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<proto> {
@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<cholder>;
}

# 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<proto> {
$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),
Expand Down
27 changes: 0 additions & 27 deletions dotnet/runtime/Init.cs
Expand Up @@ -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;
}

Expand All @@ -80,30 +77,6 @@ private static void RegisterRepresentations()
}
}

/// <summary>
/// Adds to the low level code object's HOW.
/// </summary>
/// <param name="KnowHOW"></param>
/// <param name="instance"></param>
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<RakudoCodeRef.Instance>();
Instance.Dispatchees.Add(Dispatchee);
return CaptureHelper.Nil();
})
}));
}

/// <summary>
/// Sets up the bootstrapping setting that we use to compile the
/// real setting.
Expand Down
5 changes: 0 additions & 5 deletions dotnet/runtime/Metamodel/Representations/RakudoCodeRef.cs
Expand Up @@ -43,11 +43,6 @@ public sealed class Instance : RakudoObject
/// </summary>
public Context CurrentContext;

/// <summary>
/// Things we have control over the dispatch of.
/// </summary>
public List<Instance> Dispatchees;

public Instance(SharedTable STable)
{
this.STable = STable;
Expand Down
2 changes: 2 additions & 0 deletions dotnet/runtime/Rakudo.Net.csproj
Expand Up @@ -72,6 +72,8 @@
<Compile Include="Metamodel\Representations\P6hash.cs" />
<Compile Include="Metamodel\Representations\P6opaque.cs" />
<Compile Include="Runtime\CaptureHelper.cs" />
<Compile Include="Runtime\MultiDispatch\LexicalCandidateFinder.cs" />
<Compile Include="Runtime\MultiDispatch\MultiDispatcher.cs" />
<Compile Include="Runtime\Ops.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Runtime\CodeObjectUtility.cs" />
Expand Down
39 changes: 39 additions & 0 deletions 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
{
/// <summary>
/// Finds all candidates that we may dispatch to.
/// </summary>
public static class LexicalCandidateFinder
{
/// <summary>
/// Locates all matching candidates between the two scopes.
/// </summary>
/// <param name="FromScope"></param>
/// <param name="ToScope"></param>
/// <param name="Name"></param>
/// <returns></returns>
public static List<RakudoCodeRef.Instance> FindCandidates(Context CallerScope, Context ProtoScope, string CandidateHolderName)
{
var Result = new List<RakudoCodeRef.Instance>();
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;
}
}
}
22 changes: 22 additions & 0 deletions 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
{
/// <summary>
/// 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.
/// </summary>
public static class MultiDispatcher
{
public static RakudoCodeRef.Instance FindBestCandidate(List<RakudoCodeRef.Instance> Candidates, RakudoObject Capture)
{
throw new NotImplementedException();
}
}
}
17 changes: 17 additions & 0 deletions dotnet/runtime/Runtime/Ops.cs
Expand Up @@ -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);
}

/// <summary>
/// Entry point to multi-dispatch over the candidates in the inner
/// dispatcher.
/// </summary>
/// <param name="TC"></param>
/// <returns></returns>
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);
}
}
}

0 comments on commit a389552

Please sign in to comment.