/
Rosella.winxed
229 lines (201 loc) · 7.51 KB
/
Rosella.winxed
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
222
223
224
225
226
227
228
/*
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.invalid(__FUNCTION__, "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.invalid(__FUNCTION__, "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.invalid(__FUNCTION__, "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.invalid(__FUNCTION__, "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.invalid(__FUNCTION__, "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
function __load_rosella_libraries[anon](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 [optional], int has_trigger [opt_flag])
{
var pf = load_packfile(file);
if (has_trigger && 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.invalid(__FUNCTION__, "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.invalid(__FUNCTION__, "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;
}
}
function get_pmc_keyed_hash()
{
var h = {};
h.set_key_type(3);
return h;
}
}