Skip to content
This repository
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 222 lines (194 sloc) 7.396 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
/*
    The Rosella namespace is the base namespace of the Rosella library. All
    Rosella libraries are in their own namespaces nested under the ["Rosella"]
    namespace.

    This namespace provides a handful of basic functions which are used
    throughout rosella for some base functionality. These functions can be
    broken into two general groups: functions for creating new objects, and
    functions for working with types.
*/
namespace Rosella
{
    function get_winxed_compiler()
    {
        var c = compreg("winxed");
        if (c != null)
            return c;
        load_language("winxed");
        c = compreg("winxed");
        if (c != null)
            return c;
        Rosella.Error.error("Cannot get Winxed compiler object");
    }

    /* Allocation / Construction Functions
        These functions allocate a new object using some kind of proto-
        or meta-object. This meta-object can be a Class PMC, a PMC which can
        be used to look up a class (String, String array, NameSpace, Key),
        or something from the P6object system (P6metaclass, P6protoobject)
    */

    // Allocate a fresh new object from the meta-object. Do not manipulate it,
    // initialize it, or call any methods on it.
    function alloc(var proto)
    {
        if (proto == null)
            Rosella.Error.error("type may not be null");
        var object;
        if (proto instanceof 'P6protoobject')
            object = proto.new();
        else {
            var obj_class = get_type_class(proto);
            object = new_pmc(obj_class);
        }
        return object;
    }

    // P6-ish initializer routine. Allocate a new object and call the BUILD
    // method on it, if it is defined.
    function build(var proto, var pos [slurpy], var named [slurpy, named])
    {
        var object = alloc(proto);
        var method = find_named_method(object, "BUILD");
        if (method != null)
            object.*method(pos:[flat], named:[flat,named]);
        return object;
    }

    // Construct a new object. Allocate a fresh object of the given type and
    // call the class constructor. The class constructor is a method with the
    // same name as the short name of the Class.
    function construct(var proto, var pos [slurpy], var named [slurpy,named])
    {
        var object = alloc(proto);
        var class_obj = get_type_class(proto);
        var method = find_named_method(object, class_obj.name());
        if (method != null)
            object.*method(pos:[flat], named:[flat,named]);
        return object;
    }

    /* Type Manipulation Functions
        These functions take a meta-object (one of the types listed above)
        and extracts useful information from them in a common way.
    */

    // Get the fully-qualified string name of the type
    function get_type_name(var type)
    {
        if (type == null)
            Rosella.Error.error("type may not be null");
        if (type instanceof "String")
            return type;

        if (type instanceof "P6protoobject")
            type = type.HOW().get_parrotclass(type).get_namespace();
        else if (type instanceof "P6metaclass")
            type = type.get_parrotclass(type).get_namespace();
        else if (type instanceof "Class")
            type = type.get_namespace();
        else if (type instanceof "Key")
            type = get_namespace(type);

        if (type instanceof "NameSpace")
            return join(";", type.get_name());

        if (does(type, "array"))
            return join(";", type);
        return string(type);
    }

    // Get the Parrot Class PMC associated with the type.
    function get_type_class(var type)
    {
        if (type == null)
            Rosella.Error.error("type may not be null");

        if (type instanceof "P6metaclass")
            return type.get_parrotclass(type);
        if (type instanceof "P6protoobject")
            return type.HOW().get_parrotclass(type);
        if (type instanceof "Class")
            return type;

        if (type instanceof "String")
            type = split(";", type);
        return get_class(type);
    }

    // Determine if the given object is an instance of the given type.
    function isa_type(var type, var object)
    {
        if (type == null)
            Rosella.Error.error("type may not be null");

        var class_test = get_type_class(type);
        return isa(object, class_test);
    }

    /* Bytecode Management Functions
    */

    // Initialize the Rosella library, loading in any necessary files.
    function initialize_rosella(var libs [slurpy])
    {
        var core = load_packfile("rosella/core.pbc");
        init_bytecode(core, "load");
        __load_rosella_libraries(libs);
    }

    // Load a Rosella library, by name
    function load_rosella_library(var libs [slurpy])
    {
        __load_rosella_libraries(libs);
    }

    // Load an array of rosella libraries
    inline __load_rosella_libraries(var libs)
    {
        for (string lib in libs) {
            string lib_name = sprintf("rosella/%s.pbc", [lib]);
            var pf = load_packfile(lib_name);
            init_bytecode(pf, "load");
        }
    }

    // Load in the bytecode library, executing the given trigger, if any.
    function load_bytecode_file(string file, string trigger = null)
    {
        var pf = load_packfile(file);
        if (trigger != "" && trigger != null)
            init_bytecode(pf, trigger);
        return pf;
    }

    // Initialize the bytecode, executing subs with the given trigger
    function init_bytecode(var pf, string trigger)
    {
        if (!pf.is_initialized(trigger)) {
            pf.mark_initialized(trigger);
            var subs = pf.subs_by_tag(trigger);
            for (var sub in subs)
                sub();
        }
    }

    /* Method-Utility Functions
        These functions help do things with functions and methods. These are
        NOT part of the standard API of the Rosella namespace, they only exist
        to help deal with shortcomings in various parts of the toolchain.
        These functions will disappear when they are no longer needed
    */

    // find a method PMC on the given object without throwing an exception on
    // failure.
    function find_named_method(var object, string meth_name)
    {
        if (object == null || meth_name == null)
            Rosella.Error.error("object and meth_name may not be null");

        if (!can(object, meth_name))
            return null;
        return find_method(object, meth_name);
    }

    // Invoke the given method on the object with the given parameters.
    // The method parameter can be a method object or a String with the name
    // of the method to lookup.
    function invoke_method(var obj, var method, var p, var n)
    {
        if (method instanceof 'String') {
            var real_method = find_named_method(obj, method);
            if (real_method == null)
                Rosella.Error.error("Cannot find method '%s'", method);
            method = real_method;
        }
        return obj.*method(p:[flat], n:[flat,named]);
    }

    // Get a unique count number, which is guaranteed to be unique throughout
    // the Rosella library for the duration of the program.
    function get_unique_count()
    {
        int i = 0;
        while(1) {
            i = i + 1;
            yield i;
        }
    }
}

Something went wrong with that request. Please try again.