Package Rakudo.Runtime

Source Code of Rakudo.Runtime.SignatureBinder

package Rakudo.Runtime;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import Rakudo.Metamodel.RakudoObject;
import Rakudo.Metamodel.Representations.P6capture;
import Rakudo.Metamodel.Representations.P6list;
import Rakudo.Metamodel.Representations.P6mapping;
import Rakudo.Runtime.Context;



/// <summary>
/// Simple signature binder implementation.
/// </summary>
public class SignatureBinder // C# has public static class
{
    /// <summary>
    /// Singleton empty positionals array.
    /// </summary>
    private static RakudoObject[] EmptyPos = new RakudoObject[0];

    /// <summary>
    /// Single empty nameds hash.
    /// </summary>
    private static HashMap<String, RakudoObject> EmptyNamed = new HashMap<String, RakudoObject>();

    /// <summary>
    /// Binds the capture against the given signature and stores the
    /// bound values into variables in the lexpad.
    ///
    /// XXX No type-checking is available just yet. :-(
    ///
    /// XXX No support for nameds mapping to positionals yet either.
    ///
    /// (In other words, this kinda sucks...)
    /// </summary>
    /// <param name="C"></param>
    /// <param name="Capture"></param>
    public static void Bind(ThreadContext tc, Context c, RakudoObject capture)
// DROP    public static void Bind(Context tc, RakudoObject capture)
    {
        // Make sure the object is really a low level capture (don't handle
        // otherwise yet) and grab the pieces.
        P6capture.Instance nativeCapture = (P6capture.Instance)capture;
        if (nativeCapture == null)
            throw new UnsupportedOperationException("Can only deal with native captures at the moment");
        RakudoObject[] positionals = nativeCapture.Positionals != null ? nativeCapture.Positionals : EmptyPos;
        HashMap<String,RakudoObject> nameds = nativeCapture.Nameds != null ? nativeCapture.Nameds : EmptyNamed;
        HashMap<String, Boolean> seenNames = null; // C# has <string, bool> (a value type)

        // See if we have to do any flattening.
// TODO if (NativeCapture.FlattenSpec != null)
//          Flatten(nativeCapture.FlattenSpec, positionals, nameds); // C# has ref Positionals, ref Nameds :( http://javadude.com/articles/passbyvalue.htm and http://genamics.com/developer/csharp_comparative_part9.htm

        // If we have no signature, that's same as an empty signature.
        Signature sig = c.StaticCodeObject.Sig;
        if (sig == null)
            return;

        // Current positional.
        int curPositional = 0;

        // Iterate over the parameters.
        Parameter[] params = sig.Parameters;
        int numParams = params.length;
        for (int i = 0; i < numParams; i++)
        {
            Parameter param = params[i];

            // Positional required?
            if (param.Flags == Parameter.POS_FLAG)
            {
                if (curPositional < positionals.length)
                {
                    // We have an argument, just bind it.
                    c.LexPad.Storage[param.VariableLexpadPosition] = positionals[curPositional];
                }
                else
                {
                    throw new UnsupportedOperationException("Not enough positional parameters; got " +
                        Integer.toString(curPositional) + " but needed " +
                        Integer.toString(NumRequiredPositionals(c.StaticCodeObject.Sig)));
                }

                // Increment positional counter.
                curPositional++;
            }

            // Positional optional?
            else if (param.Flags == Parameter.OPTIONAL_FLAG)
            {
                if (curPositional < positionals.length)
                {
                    // We have an argument, just bind it.
                    c.LexPad.Storage[param.VariableLexpadPosition] = positionals[curPositional];
                    curPositional++;
                }
                else
                {
                    // Default value, vivification.
                    // ((RakudoCodeRef.Instance)Param.DefaultValue).CurrentContext = TC.CurrentContext;
                    c.LexPad.Storage[param.VariableLexpadPosition] = param.DefaultValue.getSTable().Invoke(tc, param.DefaultValue, capture);
                }
            }

            // Named slurpy?
            else if ((param.Flags & Parameter.NAMED_SLURPY_FLAG) != 0)
            {
                RakudoObject slurpyHolder = tc.DefaultHashType.getSTable().REPR.instance_of(tc, tc.DefaultHashType);
                c.LexPad.Storage[param.VariableLexpadPosition] = slurpyHolder;
                for (String name : nameds.keySet().toArray(new String[0]))
                    if (seenNames == null || !seenNames.containsKey(name))
                        Ops.llmapping_bind_at_key(tc, slurpyHolder,
                            Ops.box_str(tc, name, tc.DefaultStrBoxType),
                            nameds.get(name));
            }

            // Positional slurpy?
            else if ((param.Flags & Parameter.POS_SLURPY_FLAG) != 0)
            {
                RakudoObject slurpyHolder = tc.DefaultArrayType.getSTable().REPR.instance_of(tc, tc.DefaultArrayType);
                c.LexPad.Storage[param.VariableLexpadPosition] = slurpyHolder;
                int j;
                for (j = curPositional; j < positionals.length; j++)
                    Ops.lllist_push(tc, slurpyHolder, positionals[j]);
                curPositional = j;
            }

            // Named?
            else if (param.Name != null)
            {
                // Yes, try and get argument.
                if (nameds.containsKey(param.Name))
                {
                    // We have an argument, just bind it.
                    RakudoObject value = nameds.get(param.Name);
                    c.LexPad.Storage[param.VariableLexpadPosition] = value;
                    if (seenNames == null)
                        seenNames = new HashMap<String, Boolean>();
                    seenNames.put(param.Name, true);
                }
                else
                {
                    // Optional?
                    if ((param.Flags & Parameter.OPTIONAL_FLAG) == 0)
                    {
                        throw new UnsupportedOperationException("Required named parameter " + param.Name + " missing");
                    }
                    else
                    {
                        c.LexPad.Storage[param.VariableLexpadPosition] = param.DefaultValue.getSTable().Invoke(tc, param.DefaultValue, capture);
                    }
                }
            }

            // Otherwise, WTF?
            else
            {

            }
        }

        // Ensure we had enough positionals.
        int possiesInCapture = positionals.length;
        if (curPositional != possiesInCapture)
            throw new UnsupportedOperationException("Too many positional arguments passed; expected " +
                Integer.toString(NumRequiredPositionals(c.StaticCodeObject.Sig)) +
                " but got " + Integer.toString(possiesInCapture));

        // XXX TODO; Ensure we don't have leftover nameds.
    }

    /// <summary>
    /// The number of positionals we require.
    /// </summary>
    /// <param name="Sig"></param>
    /// <returns></returns>
    private static int NumRequiredPositionals(Signature sig)
    {
        int num = 0;
        for (Parameter param : sig.Parameters)
            if (param.Flags != 0 || param.Name != null)
                break;
            else
                num++;
        return num;
    }

    /// <summary>
    /// Flattens arguments into the positionals list or the nameds. This
    /// is pretty straightforward, could be optimized in various ways,
    /// such as special case where we only have one arg which is the whole
    /// parameter set.
    /// </summary>
    /// <param name="FlattenSpec"></param>
    /// <param name="Positionals"></param>
    /// <param name="Naneds"></param>
// TODO  private static void Flatten(int[] FlattenSpec, ref RakudoObject[] Positionals, ref Dictionary<string, RakudoObject> Naneds)
    private static void Flatten(int[] FlattenSpec, RakudoObject[] Positionals, HashMap<String, RakudoObject> Naneds)
    {
        // We'll build new positional and nameds.
        ArrayList<RakudoObject> NewPositionals = new ArrayList<RakudoObject>();
        HashMap<String, RakudoObject> NewNameds = new HashMap<String, RakudoObject>(Naneds);

        // Go through positional arguments and look for things to flatten.
        for (int i = 0; i < Positionals.length; i++)
        {
            if (FlattenSpec[i] == CaptureHelper.FLATTEN_NONE)
            {
                NewPositionals.add(Positionals[i]);
            }
            else if (FlattenSpec[i] == CaptureHelper.FLATTEN_POS)
            {
                // XXX For now rely on it being a P6list but in the future we
                // should handle other cases.
                P6list.Instance Flattenee = (P6list.Instance)Positionals[i];
                if (Flattenee != null)
                {
                    NewPositionals.addAll(Flattenee.Storage);
                }
                else
                {
                    throw new UnsupportedOperationException("Currently can only flatten a P6list");
                }
            }
            else if (FlattenSpec[i] == CaptureHelper.FLATTEN_NAMED)
            {
                // XXX For now rely on it being a P6mapping but in the future we
                // should handle other cases.
                P6mapping.Instance Flattenee = (P6mapping.Instance)Positionals[i];
                if (Flattenee != null)
                {
                    for (Map.Entry entryPair : Flattenee.Storage.entrySet()) // HashMap<String,RakudoObject>
                        NewNameds.put((String)entryPair.getKey(), (RakudoObject)entryPair.getValue());
                }
                else
                {
                    throw new UnsupportedOperationException("Currently can only flatten a P6mapping");
                }
            }
        }

        // Put updated positionals and nameds in place.
        Positionals = (RakudoObject[])NewPositionals.toArray();
        Naneds = NewNameds;
    }
}
TOP

Related Classes of Rakudo.Runtime.SignatureBinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.