Package Rakudo.Metamodel.Representations

Source Code of Rakudo.Metamodel.Representations.P6opaque$Instance

package Rakudo.Metamodel.Representations;

import java.util.HashMap;

import Rakudo.Metamodel.Hints;
import Rakudo.Metamodel.RakudoObject;
import Rakudo.Metamodel.Representation;
import Rakudo.Metamodel.SharedTable;
import Rakudo.Runtime.CaptureHelper;
import Rakudo.Runtime.Ops;
import Rakudo.Runtime.ThreadContext;
import Rakudo.Serialization.SerializationContext;

/// <summary>
/// This is a first cut implementation of the P6opaque representation.
/// Eventually it's going to need to handle native types too, and we
/// want to get an instance down to a single object allocation if we
/// can. Alas, that's Quite Tricky to write, so for now we just do
/// something easy, but at least with the hints.
/// </summary>
public final class P6opaque implements Representation // C# has sealed
{
    /// <summary>
    /// This stores a mapping of classes/names to slots in the event
    /// we need to do a lookup.
    /// </summary>
    protected HashMap<RakudoObject, HashMap<String, Integer>> SlotAllocation = new HashMap<RakudoObject, HashMap<String, Integer>>();
    protected int Slots = 0;

    /// <summary>
    /// This is what an instance of a P6opaque looks like. The SlotStorage
    /// is an array where we'll store most attributes, so we can look them
    /// up by index. There's also an unallocated spill-over store for any
    /// attributes that are added through augment, or in MI cases.
    /// </summary>
    private final class Instance extends RakudoObject
    {
        public RakudoObject[] SlotStorage;
        public HashMap<RakudoObject, HashMap<String, RakudoObject>> SpillStorage;
        public Instance(SharedTable sTable)
        {
            this.setSTable(sTable);
        }
    }

    /// <summary>
    /// Creates a type object that references the given HOW and sets up
    /// the STable with a new REPR instance too.
    /// </summary>
    /// <param name="HOW"></param>
    /// <returns></returns>
    public RakudoObject type_object_for(ThreadContext tc, RakudoObject MetaPackage)
    {
        SharedTable sTable = new SharedTable();
        sTable.HOW = MetaPackage;
        sTable.REPR = new P6opaque();
        sTable.WHAT = new Instance(sTable);
        return sTable.WHAT;
    }

    /// <summary>
    /// Allocates and returns a new object based upon the type object
    /// supplied.
    /// </summary>
    /// <param name="HOW"></param>
    /// <returns></returns>
    public RakudoObject instance_of(ThreadContext tc, RakudoObject what)
    {
        if (SlotAllocation == null)
            ComputeSlotAllocation(tc, what);
        Instance object = new Instance(what.getSTable());
        object.SlotStorage = new RakudoObject[Slots];
        return object;
    }

    /// <summary>
    /// Checks if the object is defined, which boils down to "is
    /// this a type object", which in trun means "did we allocate
    /// any storage".
    /// </summary>
    /// <param name="object"></param>
    /// <returns></returns>
    public boolean defined(ThreadContext tc, RakudoObject object)
    {
        return ((Instance)object).SlotStorage != null;
    }

    /// <summary>
    /// Gets an attribute.
    /// </summary>
    /// <param name="object"></param>
    /// <param name="ClassHandle"></param>
    /// <param name="Name"></param>
    /// <returns></returns>
    public RakudoObject get_attribute(ThreadContext tc, RakudoObject object, RakudoObject classHandle, String name)
    {
        Instance I = (Instance)object;

        // Try the slot allocation first.
        if (SlotAllocation != null && SlotAllocation.containsKey(classHandle)) {
            HashMap<String, Integer> classAllocation = SlotAllocation.get(classHandle);
            if (classAllocation.containsKey(name)) {
                return I.SlotStorage[classAllocation.get(name)];
            }
        }
        // Fall back to the spill storage.
        if (I.SpillStorage != null && I.SpillStorage.containsKey(classHandle))
        {
            HashMap<String,RakudoObject> classStore = I.SpillStorage.get(classHandle);
            if (classStore.containsKey(name))
                return classStore.get(name);
        }

        return null;
    }

    /// <summary>
    /// Gets the attribute, using the hint if possible.
    /// </summary>
    /// <param name="object"></param>
    /// <param name="ClassHandle"></param>
    /// <param name="Name"></param>
    /// <param name="Hint"></param>
    /// <returns></returns>
    public RakudoObject get_attribute_with_hint(ThreadContext tc, RakudoObject object, RakudoObject classHandle, String name, int hint)
    {
        Instance I = (Instance)object;
        if (hint < I.SlotStorage.length)
        {
            return I.SlotStorage[hint];
        }
        else
        {
            if (I.SpillStorage != null && I.SpillStorage.containsKey(classHandle))
            {
                HashMap<String,RakudoObject> classStore = I.SpillStorage.get(classHandle);
                if (classStore.containsKey(name))
                    return classStore.get(name);
            }
            return null;
        }
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="object"></par    /// <param name="ClassHandle"></param>
    /// <param name="Name"></param>
    /// <param name="Value"></param>
    public void bind_attribute(ThreadContext tc, RakudoObject object, RakudoObject classHandle, String name, RakudoObject value)
    {
        Instance I = (Instance)object;

        // Try the slot allocation first.
        if (SlotAllocation != null && SlotAllocation.containsKey(classHandle)) {
            HashMap<String, Integer> classAllocation = SlotAllocation.get(classHandle);
            if (classAllocation.containsKey(name))
            {
                int position = classAllocation.get(name);
                I.SlotStorage[position] = value;
                return;
            }
        }

        // Fall back to the spill storage.
        if (I.SpillStorage == null)
            I.SpillStorage = new HashMap<RakudoObject, HashMap<String, RakudoObject>>();
        if (!I.SpillStorage.containsKey(classHandle))
            I.SpillStorage.put(classHandle, new HashMap<String, RakudoObject>());
        HashMap<String,RakudoObject> classStore = I.SpillStorage.get(classHandle);
//      if (classStore.ContainsKey(Name)) // redundant on a HashMap
//          classStore[Name] = Value;
//      else
            classStore.put(name, value);
    }

    /// <summary>
    /// Bind the attribute, using the hint if possible.
    /// </summary>
    /// <param name="object"></param>
    /// <param name="ClassHandle"></param>
    /// <param name="Name"></param>
    /// <param name="Hint"></param>
    /// <param name="Value"></param>
    public void bind_attribute_with_hint(ThreadContext tc, RakudoObject object, RakudoObject classHandle, String name, int hint, RakudoObject value)
    {
        Instance I = (Instance)object;
        if (hint < I.SlotStorage.length)
        {
            I.SlotStorage[hint] = value;
        }
        else if ((hint = hint_for(tc, classHandle, name)) != Hints.NO_HINT && hint < I.SlotStorage.length)
        {
            I.SlotStorage[hint] = value;
        }
        else
        {
            if (I.SpillStorage == null)
                I.SpillStorage = new HashMap<RakudoObject, HashMap<String, RakudoObject>>();
            if (!I.SpillStorage.containsKey(classHandle))
                I.SpillStorage.put(classHandle, new HashMap<String, RakudoObject>());
            HashMap<String, RakudoObject> classStore = I.SpillStorage.get(classHandle);
//          if (ClassStore.ContainsKey(Name)) // redundant on a HashMap
//              ClassStore.put(Name, Value);
//          else
                classStore.put(name, value);
        }
    }

    /// <summary>
    /// Checks if we have a hint for the given class and name, and if
    /// so returns it.
    /// </summary>
    /// <param name="ClassHandle"></param>
    /// <param name="Name"></param>
    /// <returns></returns>
    public int hint_for(ThreadContext tc, RakudoObject classHandle, String name)
    {
        if (SlotAllocation.containsKey(classHandle) && SlotAllocation.get(classHandle).containsKey(name))
            return SlotAllocation.get(classHandle).get(name);
        else
            return Hints.NO_HINT;
    }

    public void set_int(ThreadContext tc, RakudoObject object, int Value)
    {
        throw new UnsupportedOperationException("This type of representation cannot box a native int");
    }

    public int get_int(ThreadContext tc, RakudoObject object)
    {
        throw new UnsupportedOperationException("This type of representation cannot unbox to a native int");
    }

    public void set_num(ThreadContext tc, RakudoObject object, double Value)
    {
        throw new UnsupportedOperationException("This type of representation cannot box a native num");
    }

    public double get_num(ThreadContext tc, RakudoObject object)
    {
        throw new UnsupportedOperationException("This type of representation cannot unbox to a native num");
    }

    public void set_str(ThreadContext tc, RakudoObject object, String Value)
    {
        throw new UnsupportedOperationException("This type of representation cannot box a native String");
    }

    public String get_str(ThreadContext tc, RakudoObject object)
    {
        throw new UnsupportedOperationException("This type of representation cannot unbox to a native String");
    }
    private void ComputeSlotAllocation(ThreadContext tc, RakudoObject WHAT)
    {
        // Allocate slot mapping table.
        SlotAllocation = new HashMap<RakudoObject, HashMap<String, Integer>>();

        // Walk through the parents list.
        RakudoObject currentClass = WHAT;
        int currentSlot = 0;
        while (currentClass != null)
        {
            // Get attributes and iterate over them.
            RakudoObject HOW = currentClass.getSTable().HOW;
            RakudoObject attributesMeth = HOW.getSTable().FindMethod(tc, HOW, "attributes", Hints.NO_HINT);
            HashMap<String, RakudoObject> localBoxInt1 = new HashMap<String, RakudoObject>();
            localBoxInt1.put("local", Ops.box_int(tc, 1, tc.DefaultBoolBoxType));
            RakudoObject attributes = attributesMeth.getSTable().Invoke(tc, attributesMeth, CaptureHelper.FormWith(
                new RakudoObject[] { HOW, currentClass },
                localBoxInt1)); // new HashMap<String, RakudoObject>() { { "local", Ops.box_int(tc, 1, tc.DefaultBoolBoxType) } }));
            RakudoObject attributesElemsMeth = attributes.getSTable().FindMethod(tc, attributes, "elems", Hints.NO_HINT);
            int attributesElems = Ops.unbox_int(tc, attributesElemsMeth.getSTable().Invoke(tc, attributesElemsMeth,
                CaptureHelper.FormWith(new RakudoObject[] { attributes })));
            RakudoObject attrAtPosMeth = attributes.getSTable().FindMethod(tc, attributes, "at_pos", Hints.NO_HINT);
            for (int i = 0; i < attributesElems; i++)
            {
                // Get the attribute, then get its name.
                RakudoObject attr = attrAtPosMeth.getSTable().Invoke(tc, attrAtPosMeth, CaptureHelper.FormWith(
                    new RakudoObject[] { attributes, Ops.box_int(tc, i, tc.DefaultIntBoxType) }));
                RakudoObject nameMeth = attr.getSTable().FindMethod(tc, attr, "name", Hints.NO_HINT);
                String name = Ops.unbox_str(tc, attr.getSTable().Invoke(tc, nameMeth, CaptureHelper.FormWith(
                    new RakudoObject[] { attr })));

                // Allocate a slot.
                if (!SlotAllocation.containsKey(currentClass))
                    SlotAllocation.put(currentClass, new HashMap<String, Integer>());
                SlotAllocation.get(currentClass).put(name, currentSlot);
                currentSlot++;
            }

            // Find the next parent(s).
            RakudoObject parentsMeth = HOW.getSTable().FindMethod(tc, HOW, "parents", Hints.NO_HINT);
            HashMap<String,RakudoObject> localBoxInt2 = new HashMap<String,RakudoObject>();
            localBoxInt2.put("local", Ops.box_int(tc, 1, tc.DefaultBoolBoxType));
            RakudoObject parents = parentsMeth.getSTable().Invoke(tc, parentsMeth, CaptureHelper.FormWith(
                new RakudoObject[] { HOW, currentClass },
                localBoxInt2)); // new HashMap<String,RakudoObject>() { { "local", Ops.box_int(tc, 1, tc.DefaultBoolBoxType) } }));
            // Check how many parents we have.
            RakudoObject parentElemsMeth = parents.getSTable().FindMethod(tc, parents, "elems", Hints.NO_HINT);
            int parentElems = Ops.unbox_int(tc, parentElemsMeth.getSTable().Invoke(tc, parentElemsMeth,
                CaptureHelper.FormWith(new RakudoObject[] { parents })));
            if (parentElems == 0)
            {
                // We're done. \o/
                Slots = currentSlot;
                break;
            }
            else if (parentElems > 1)
            {
                // Multiple inheritance, so we can't compute this hierarchy.
                SlotAllocation = new HashMap<RakudoObject, HashMap<String, Integer>>();
                return;
            }
            else
            {
                // Just one. Get next parent.
                RakudoObject atPosMeth = parents.getSTable().FindMethod(tc, parents, "at_pos", Hints.NO_HINT);
                currentClass = atPosMeth.getSTable().Invoke(tc, atPosMeth, CaptureHelper.FormWith(
                    new RakudoObject[] { parents, Ops.box_int(tc, 0, tc.DefaultIntBoxType) }));
            }
        }
    }
}
TOP

Related Classes of Rakudo.Metamodel.Representations.P6opaque$Instance

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.