Package Rakudo.Metamodel.KnowHOW

Source Code of Rakudo.Metamodel.KnowHOW.KnowHOWBootstrapper

package Rakudo.Metamodel.KnowHOW;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import Rakudo.Metamodel.ISpecialFindMethod;
import Rakudo.Metamodel.KnowHOW.KnowHOWREPR;
import Rakudo.Metamodel.RakudoObject;
import Rakudo.Metamodel.Representation;
import Rakudo.Metamodel.Representations.P6capture;
import Rakudo.Metamodel.Representations.P6list;
import Rakudo.Metamodel.Representations.RakudoCodeRef;
import Rakudo.Metamodel.REPRRegistry;
import Rakudo.Metamodel.SharedTable;
import Rakudo.Runtime.CaptureHelper;
import Rakudo.Runtime.CodeObjectUtility;
import Rakudo.Runtime.Ops;
import Rakudo.Runtime.ThreadContext;

/// <summary>
/// Contains the logic that bootstraps KnowHOW, the foundation
/// for implementing the various other bits of the object model.
/// Works in conjunction with KnowHOWREPR.
/// </summary>
public class KnowHOWBootstrapper  // C# has public static
{
    /// <summary>
    /// Bootstraps the KnowHOW. This is were things "bottom out" in the
    /// meta-model so it's a tad loopy. Basically, we create a KnowHOW
    /// type object. We then create an instance from that and add a
    /// bunch of methods to it. However, we also give it a special
    /// STable with FindMethod overridden in it to go looking right
    /// into the methods dictionary.
    /// </summary>
    /// <returns></returns>
    public static RakudoObject Bootstrap()
    {
        // Create our KnowHOW type object. Note we don't have a HOW
        // just yet, so pass in null.
        Representation REPR = REPRRegistry.get_REPR_by_name("KnowHOWREPR");
        RakudoObject KnowHOW = REPR.type_object_for(null,null);

        // We'll set up a dictionary of our various methods to go into
        // KnowHOW's HOW, since we'll want to work with them a bit.
        HashMap<String, RakudoObject> KnowHOWMeths = new HashMap<String, RakudoObject>();
        KnowHOWMeths.put("new_type", CodeObjectUtility.WrapNativeMethod( new RakudoCodeRef.IFunc_Body() { // C# has a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // We first create a new HOW instance.
                RakudoObject knowHOWTypeObj = CaptureHelper.GetPositional(capture, 0);
                RakudoObject HOW = knowHOWTypeObj.getSTable().REPR.instance_of(tc, knowHOWTypeObj.getSTable().WHAT);

                // If we have a name arg, stash that value away.
                RakudoObject typeName = CaptureHelper.GetNamed(capture, "name");
                ((KnowHOWREPR.KnowHOWInstance)HOW).Name = typeName != null ? typeName : Ops.box_str(tc, "<anon>");

                // Now create a new type object to go with it of the
                // desired REPR; we default to P6opaque (note that the
                // KnowHOW repr only knows how to store a table of
                // methods and attributes, it can't be used for an
                // instance object that actually wants to store some
                // instance data).
                RakudoObject REPRName = CaptureHelper.GetNamed(capture, "repr");
                if (REPRName != null)
                {
                    // Look up the REPR.
                    Representation REPRToUse = REPRRegistry.get_REPR_by_name(Ops.unbox_str(null, REPRName));
                    return REPRToUse.type_object_for(null, HOW);
                }
                else
                {
                    // Just go with the P6opaque REPR.
                    return REPRRegistry.get_REPR_by_name("P6opaque").type_object_for(tc, HOW);
                }
            }
        }));
        KnowHOWMeths.put("add_attribute", CodeObjectUtility.WrapNativeMethod( new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)CaptureHelper.GetPositional(capture, 0);
                RakudoObject Attr = CaptureHelper.GetPositional(capture, 2);
                HOW.Attributes.add(Attr);
                return CaptureHelper.Nil();
            }
        }));
        KnowHOWMeths.put("add_method", CodeObjectUtility.WrapNativeMethod( new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)CaptureHelper.GetPositional(capture, 0);
                String name = CaptureHelper.GetPositionalAsString(capture, 2);
                RakudoObject method = CaptureHelper.GetPositional(capture, 3);
                HOW.Methods.put(name, method);
                return CaptureHelper.Nil();
            }
        }));
        KnowHOWMeths.put("find_method", CodeObjectUtility.WrapNativeMethod( new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // We go to some effort to be really fast in here, 'cus it's a
                // hot path for dynamic dispatches.
                RakudoObject[] Positionals = ((P6capture.Instance)capture).Positionals;
                assert Positionals.length >= 3;
                KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)Positionals[0];
                if (HOW.Methods.containsKey(Ops.unbox_str(tc, Positionals[2])))
                    return HOW.Methods.get(Ops.unbox_str(tc, Positionals[2]));
                else {
                    // throw new NoSuchMethodException("No such method " + Ops.unbox_str(tc, Positionals[1]));
                    throw new UnsupportedOperationException("No such method " + Ops.unbox_str(tc, Positionals[1]));
                }
            }
        }));
        KnowHOWMeths.put("compose", CodeObjectUtility.WrapNativeMethod( new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                RakudoObject obj = CaptureHelper.GetPositional(capture, 1);
                return obj;
            }
        }));
        KnowHOWMeths.put("attributes", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // Safe to just return a P6list instance that points at
                // the same thing we hold internally, since a list is
                // immutable. However, if default list type has no HOW,
                // we will see if we can find one that does have it.
                KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)CaptureHelper.GetPositional(capture, 0);
                RakudoObject listType = MostDefinedListType(tc);
                RakudoObject result = listType.getSTable().REPR.instance_of(tc, listType);
                ((P6list.Instance)result).Storage = HOW.Attributes;
                return result;
            }
        }));
        KnowHOWMeths.put("methods", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() { // an anonymous class where C# uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // Return the methods list.
                KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)CaptureHelper.GetPositional(capture, 0);
                RakudoObject listType = MostDefinedListType(tc);
                RakudoObject result = listType.getSTable().REPR.instance_of(tc, listType);
                ((P6list.Instance)result).Storage.addAll(HOW.Methods.values());
                return result;
            }
        }));
        KnowHOWMeths.put("parents", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() { // an anonymous class
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // A pure prototype never has any parents, so return an empty list.
                RakudoObject listType = MostDefinedListType(tc);
                return listType.getSTable().REPR.instance_of(tc, listType);
            }
        }));

        KnowHOWMeths.put("type_check", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() { // an anonymous class
            public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture)
            {
                // Can only match against ourselves.
                RakudoObject self = CaptureHelper.GetPositional(capture, 1);
                RakudoObject check = CaptureHelper.GetPositional(capture, 2);
                return Ops.box_int(tc, self.getSTable().WHAT == check.getSTable().WHAT ? 1 : 0, tc.DefaultBoolBoxType);
            }
        }));

        // We create a KnowHOW instance that can describe itself.
        // This means .HOW.HOW.HOW.HOW etc will always return that,
        // which closes the model up.
        KnowHOWREPR.KnowHOWInstance KnowHOWHOW = (KnowHOWREPR.KnowHOWInstance)REPR.instance_of(null,KnowHOW);
        for ( String key : KnowHOWMeths.keySet() )
            KnowHOWHOW.Methods.put(key, KnowHOWMeths.get(key));

        // We need to clone the STable.
        SharedTable sTableCopy = new SharedTable();
        sTableCopy.HOW = KnowHOWHOW;
        sTableCopy.WHAT = KnowHOW.getSTable().WHAT;
        sTableCopy.REPR = KnowHOW.getSTable().REPR;
        KnowHOWHOW.setSTable(sTableCopy);

        // And put a fake FindMethod in there that just looks in the
        // dictionary.
        KnowHOWHOW.getSTable().SpecialFindMethod = new ISpecialFindMethod() // C# has a => (lambda)
        {
            public RakudoObject SpecialFindMethod(ThreadContext tc, RakudoObject obj, String name, int hint)
            {
                HashMap<String, RakudoObject> mTable = ((KnowHOWREPR.KnowHOWInstance)obj).Methods;
                if (mTable.containsKey(name))
                    return mTable.get(name);
                else {
                    throw new UnsupportedOperationException("No such method " + name);
                }
            }
        };

        // Set this as the KnowHOW's HOW.
        KnowHOW.getSTable().HOW = KnowHOWHOW;

        // And we should be done.
        return KnowHOW;
    }

    /// <summary>
    /// Sets up the KnowHOWAttribute object/class, which actually is a
    /// KnowHOW.
    /// </summary>
    /// <returns></returns>
    public static RakudoObject SetupKnowHOWAttribute(RakudoObject knowHOW)
    {
        // Create a new HOW instance.
        KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)knowHOW.getSTable().REPR.instance_of(null, knowHOW);

        // We base the attribute on P6str, since we just want to store an
        // attribute name for now.
        RakudoObject knowHOWAttribute = REPRRegistry.get_REPR_by_name("P6str").type_object_for(null, HOW);

        // Add methods new and Str.
        HOW.Methods.put("new", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() {  // the C# version uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject obj, RakudoObject capture)
            {
                RakudoObject WHAT = CaptureHelper.GetPositional(capture, 0).getSTable().WHAT;
                String name = Ops.unbox_str(tc, CaptureHelper.GetNamed(capture, "name"));
                return Ops.box_str(tc, name, WHAT);
            }
        }));
        HOW.Methods.put("name", CodeObjectUtility.WrapNativeMethod(new RakudoCodeRef.IFunc_Body() { // the C# version uses a lambda
            public RakudoObject Invoke(ThreadContext tc, RakudoObject obj, RakudoObject capture)
            {
                RakudoObject self = CaptureHelper.GetPositional(capture, 0);
                return Ops.box_str(tc, Ops.unbox_str(tc, self), tc.DefaultStrBoxType);
            }
        }));

        return knowHOWAttribute;
    }

    /// <summary>
    /// Makes sure that we hand back an NQPList that has a HOW once it
    /// is defined. Important for the bootstrap.
    /// </summary>
    /// <param name="tc"></param>
    /// <returns></returns>
    private static RakudoObject MostDefinedListType(ThreadContext tc)
    {
        // Have a HOW? Then return it right away.
        if (tc.DefaultListType.getSTable().HOW != null)
            return tc.DefaultListType;

        // Otherwise, go and look for a list type that has one.
        tc.DefaultListType = Ops.get_lex(tc, "NQPList");
        return tc.DefaultListType;
    }
}
TOP

Related Classes of Rakudo.Metamodel.KnowHOW.KnowHOWBootstrapper

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.