1
/* Contains the logic that bootstraps KnowHOW, the foundation for implementing
2
* the various other bits of the object model. Works in conjunction with
5
#define PARROT_IN_EXTENSION
6
#include "parrot/parrot.h"
7
#include "parrot/extend.h"
8
#include "sixmodelobject.h"
9
#include "repr_registry.h"
10
#include "reprs/KnowHOWREPR.h"
11
#include "knowhow_bootstrapper.h"
13
/* Cached string constants. */
14
static STRING *repr_str = NULL;
15
static STRING *name_str = NULL;
16
static STRING *empty_str = NULL;
17
static STRING *p6opaque_str = NULL;
18
static STRING *attribute_str = NULL;
20
/* Creates a new type with this HOW as its meta-object. */
21
static void new_type(PARROT_INTERP, PMC *nci) {
23
/* We first create a new HOW instance. */
24
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
25
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
26
PMC *HOW = REPR(self)->allocate(interp, STABLE(self));
28
/* See if we have a representation name; if not default to P6opaque. */
29
STRING *repr_name = VTABLE_exists_keyed_str(interp, capture, repr_str) ?
30
VTABLE_get_string_keyed_str(interp, capture, repr_str) :
33
/* Create a new type object of the desired REPR. (Note that we can't
34
* default to KnowHOWREPR here, since it doesn't know how to actually
35
* store attributes, it's just for bootstrapping knowhow's. */
36
REPROps *repr_to_use = REPR_get_by_name(interp, repr_name);
37
PMC *type_object = repr_to_use->type_object_for(interp, HOW);
39
/* See if we were given a name; put it into the meta-object if so. */
40
STRING *name = VTABLE_exists_keyed_str(interp, capture, name_str) ?
41
VTABLE_get_string_keyed_str(interp, capture, name_str) :
43
REPR(HOW)->initialize(interp, STABLE(HOW), OBJECT_BODY(HOW));
44
((KnowHOWREPRInstance *)PMC_data(HOW))->body.name = name;
45
PARROT_GC_WRITE_BARRIER(interp, HOW);
47
/* Set .WHO to an empty hash. */
48
STABLE(type_object)->WHO = Parrot_pmc_new(interp, enum_class_Hash);
49
PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC(type_object));
51
/* Put it into capture to act as return value. */
52
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", type_object);
56
static void add_method(PARROT_INTERP, PMC *nci) {
58
/* Get methods table out of meta-object. */
59
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
60
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
61
PMC *methods = ((KnowHOWREPRInstance *)PMC_data(self))->body.methods;
63
/* Get name and method to add. */
64
STRING *name = VTABLE_get_string_keyed_int(interp, capture, 2);
65
PMC *method = VTABLE_get_pmc_keyed_int(interp, capture, 3);
67
/* Add it, and return added method as result. */
68
VTABLE_set_pmc_keyed_str(interp, methods, name, method);
69
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", method);
72
/* Adds an attribute meta-object to the list. */
73
static void add_attribute(PARROT_INTERP, PMC *nci) {
75
/* Get attributes list out of meta-object. */
76
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
77
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
78
PMC *attrs = ((KnowHOWREPRInstance *)PMC_data(self))->body.attributes;
80
/* Add meta-attribute to it. */
81
PMC *meta_attr = VTABLE_get_pmc_keyed_int(interp, capture, 2);
82
VTABLE_push_pmc(interp, attrs, meta_attr);
83
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", meta_attr);
87
static void find_method(PARROT_INTERP, PMC *nci) {
89
/* Get methods table out of meta-object and look up method. */
90
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
91
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
92
PMC *methods = ((KnowHOWREPRInstance *)PMC_data(self))->body.methods;
93
STRING *name = VTABLE_get_string_keyed_int(interp, capture, 2);
94
PMC *method = VTABLE_get_pmc_keyed_str(interp, methods, name);
96
/* Put into capture to act as return value. */
97
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", method);
100
/* Composes the meta-object. */
101
static void compose(PARROT_INTERP, PMC *nci) {
102
PMC *repr_info_hash, *repr_info, *type_info, *attr_list, *attr_iter, *unused;
103
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
104
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
105
PMC *obj = VTABLE_get_pmc_keyed_int(interp, capture, 1);
107
/* Do REPR composition. */
108
repr_info = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
109
type_info = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
110
VTABLE_push_pmc(interp, repr_info, type_info);
111
VTABLE_push_pmc(interp, type_info, obj);
112
attr_list = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
113
attr_iter = VTABLE_get_iter(interp, ((KnowHOWREPRInstance *)PMC_data(self))->body.attributes);
114
while (VTABLE_get_bool(interp, attr_iter)) {
115
PMC *attr = VTABLE_shift_pmc(interp, attr_iter);
116
PMC *attr_hash = Parrot_pmc_new(interp, enum_class_Hash);;
117
VTABLE_set_string_keyed_str(interp, attr_hash, name_str,
118
REPR(attr)->box_funcs->get_str(interp, STABLE(attr), OBJECT_BODY(attr)));
119
VTABLE_push_pmc(interp, attr_list, attr_hash);
121
VTABLE_push_pmc(interp, type_info, attr_list);
122
VTABLE_push_pmc(interp, type_info, Parrot_pmc_new(interp, enum_class_ResizablePMCArray));
123
repr_info_hash = Parrot_pmc_new(interp, enum_class_Hash);
124
VTABLE_set_pmc_keyed_str(interp, repr_info_hash, attribute_str, repr_info);
125
REPR(obj)->compose(interp, STABLE(obj), repr_info_hash);
127
/* Set up method and type caches. */
128
STABLE(obj)->method_cache = ((KnowHOWREPRInstance *)PMC_data(self))->body.methods;
129
STABLE(obj)->mode_flags = METHOD_CACHE_AUTHORITATIVE;
130
STABLE(obj)->type_check_cache_length = 1;
131
STABLE(obj)->type_check_cache = (PMC **)mem_sys_allocate(sizeof(PMC *));
132
STABLE(obj)->type_check_cache[0] = obj;
134
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", obj);
137
/* Introspects the parents. Since a KnowHOW doesn't support inheritance,
138
* just hand back an empty list. */
139
static void parents(PARROT_INTERP, PMC *nci) {
141
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
142
PMC *empty = Parrot_pmc_new(interp, enum_class_FixedPMCArray);
143
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", empty);
146
/* Introspects the attributes. For now just hand back real list. */
147
static void attributes(PARROT_INTERP, PMC *nci) {
149
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
150
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
151
PMC *attrs = ((KnowHOWREPRInstance *)PMC_data(self))->body.attributes;
152
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", attrs);
155
/* Introspects the methods. For now just hand back real method table. */
156
static void methods(PARROT_INTERP, PMC *nci) {
158
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
159
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
160
PMC *meths = ((KnowHOWREPRInstance *)PMC_data(self))->body.methods;
161
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", meths);
164
/* Introspects the MRO. That's just a list with ourself. */
165
static void mro(PARROT_INTERP, PMC *nci) {
167
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
168
PMC *obj = VTABLE_get_pmc_keyed_int(interp, capture, 1);
169
PMC *mro = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
170
VTABLE_push_pmc(interp, mro, STABLE(obj)->WHAT);
171
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", mro);
174
/* Introspects the name. */
175
static void name(PARROT_INTERP, PMC *nci) {
177
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
178
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
179
STRING *name = ((KnowHOWREPRInstance *)PMC_data(self))->body.name;
180
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "S", name);
183
/* Wraps up a C function as a raw NCI method. */
184
static PMC * wrap_c(PARROT_INTERP, void *func) {
185
PMC * const wrapped = Parrot_pmc_new(interp, enum_class_NativePCCMethod);
186
VTABLE_set_pointer_keyed_str(interp, wrapped, Parrot_str_new_constant(interp, "->"), func);
190
/* This is the find_method where things eventually bottom out. */
191
static PMC * bottom_find_method(PARROT_INTERP, PMC *obj, STRING *name, INTVAL hint) {
192
PMC *methods = ((KnowHOWREPRInstance *)PMC_data(obj))->body.methods;
193
return VTABLE_get_pmc_keyed_str(interp, methods, name);
196
/* Bootstraps the KnowHOW. This is were things "bottom out" in the meta-model
197
* so it's a tad loopy. Basically, we create a KnowHOW type object. We then
198
* create an instance from that and add a bunch of methods to it. Returns the
199
* bootstrapped object. */
200
PMC * SixModelObject_bootstrap_knowhow(PARROT_INTERP, PMC *sc) {
201
/* Create our KnowHOW type object. Note we don't have a HOW just yet, so
203
REPROps *REPR = REPR_get_by_name(interp, Parrot_str_new_constant(interp, "KnowHOWREPR"));
204
PMC *knowhow_pmc = REPR->type_object_for(interp, PMCNULL);
206
/* We create a KnowHOW instance that can describe itself. This means
207
* .HOW.HOW.HOW.HOW etc will always return that, which closes the model
208
* up. Also pull out its underlying struct. */
209
PMC *knowhow_how_pmc = REPR->allocate(interp, NULL);
210
KnowHOWREPRInstance *knowhow_how = (KnowHOWREPRInstance *)PMC_data(knowhow_how_pmc);
212
/* Need to give the knowhow_how a twiddled STable with a different
213
* dispatcher, so things bottom out. */
214
PMC *st_copy = create_stable(interp, REPR, knowhow_how_pmc);
215
STABLE_STRUCT(st_copy)->WHAT = knowhow_pmc;
216
STABLE_STRUCT(st_copy)->find_method = bottom_find_method;
217
knowhow_how->common.stable = st_copy;
219
/* Add various methods to the KnowHOW's HOW. */
220
knowhow_how->body.methods = Parrot_pmc_new(interp, enum_class_Hash);
221
knowhow_how->body.attributes = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
222
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
223
Parrot_str_new_constant(interp, "new_type"),
224
wrap_c(interp, F2DPTR(new_type)));
225
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
226
Parrot_str_new_constant(interp, "find_method"),
227
wrap_c(interp, F2DPTR(find_method)));
228
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
229
Parrot_str_new_constant(interp, "add_method"),
230
wrap_c(interp, F2DPTR(add_method)));
231
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
232
Parrot_str_new_constant(interp, "add_attribute"),
233
wrap_c(interp, F2DPTR(add_attribute)));
234
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
235
Parrot_str_new_constant(interp, "compose"),
236
wrap_c(interp, F2DPTR(compose)));
237
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
238
Parrot_str_new_constant(interp, "parents"),
239
wrap_c(interp, F2DPTR(parents)));
240
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
241
Parrot_str_new_constant(interp, "attributes"),
242
wrap_c(interp, F2DPTR(attributes)));
243
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
244
Parrot_str_new_constant(interp, "methods"),
245
wrap_c(interp, F2DPTR(methods)));
246
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
247
Parrot_str_new_constant(interp, "mro"),
248
wrap_c(interp, F2DPTR(mro)));
249
VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods,
250
Parrot_str_new_constant(interp, "name"),
251
wrap_c(interp, F2DPTR(name)));
253
/* Set name KnowHOW for the KnowHOW's HOW. */
254
knowhow_how->body.name = Parrot_str_new_constant(interp, "KnowHOW");
256
/* Set this built up HOW as the KnowHOW's HOW. */
257
STABLE(knowhow_pmc)->HOW = knowhow_how_pmc;
259
/* Give it an authoritative method cache and type check list. */
260
STABLE(knowhow_pmc)->method_cache = knowhow_how->body.methods;
261
STABLE(knowhow_pmc)->mode_flags = METHOD_CACHE_AUTHORITATIVE;
262
STABLE(knowhow_pmc)->type_check_cache_length = 1;
263
STABLE(knowhow_pmc)->type_check_cache = (PMC **)mem_sys_allocate(sizeof(PMC *));
264
STABLE(knowhow_pmc)->type_check_cache[0] = knowhow_pmc;
266
/* Set up some string constants that the methods here use. */
267
repr_str = Parrot_str_new_constant(interp, "repr");
268
name_str = Parrot_str_new_constant(interp, "name");
269
empty_str = Parrot_str_new_constant(interp, "");
270
p6opaque_str = Parrot_str_new_constant(interp, "P6opaque");
271
attribute_str = Parrot_str_new_constant(interp, "attribute");
273
/* Associate the created objects with the intial core serialization
275
VTABLE_set_pmc_keyed_int(interp, sc, 0, knowhow_pmc);
276
SC_PMC(knowhow_pmc) = sc;
277
VTABLE_set_pmc_keyed_int(interp, sc, 1, knowhow_how_pmc);
278
SC_PMC(knowhow_how_pmc) = sc;
279
STABLE(knowhow_pmc)->sc = sc;
280
STABLE(knowhow_how_pmc)->sc = sc;
285
/* Attribute new method. */
286
static void attr_new(PARROT_INTERP, PMC *nci) {
288
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
289
PMC *type = VTABLE_get_pmc_keyed_int(interp, capture, 0);
290
STRING *name = VTABLE_get_string_keyed_str(interp, capture, name_str);
291
PMC *self = REPR(type)->allocate(interp, STABLE(type));
292
REPR(self)->box_funcs->set_str(interp, STABLE(self), OBJECT_BODY(self), name);
293
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", self);
296
/* Attribute name introspection. */
297
static void attr_name(PARROT_INTERP, PMC *nci) {
299
PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
300
PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0);
301
STRING *name = REPR(self)->box_funcs->get_str(interp, STABLE(self), OBJECT_BODY(self));
302
unused = Parrot_pcc_build_call_from_c_args(interp, capture, "S", name);
305
/* Sets up a very simple attribute meta-object. Just supports having a
306
* name, and even uses the P6str representation to store it, so that's
307
* really all that it supports. */
308
PMC * SixModelObject_setup_knowhow_attribute(PARROT_INTERP, PMC *sc, PMC *knowhow) {
309
PMC *old_ctx, *cappy, *meth, *knowhow_attr, *how;
311
/* Create a new KnowHOWAttribute type using P6str repr.. */
312
meth = STABLE(knowhow)->find_method(interp, knowhow,
313
Parrot_str_new_constant(interp, "new_type"), NO_HINT);
314
old_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
315
cappy = Parrot_pmc_new(interp, enum_class_CallContext);
316
VTABLE_push_pmc(interp, cappy, knowhow);
317
VTABLE_set_string_keyed_str(interp, cappy, name_str,
318
Parrot_str_new_constant(interp, "KnowHOWAttribute"));
319
VTABLE_set_string_keyed_str(interp, cappy, repr_str,
320
Parrot_str_new_constant(interp, "P6str"));
321
Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
322
cappy = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
323
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx);
324
knowhow_attr = VTABLE_get_pmc_keyed_int(interp, cappy, 0);
325
how = STABLE(knowhow_attr)->HOW;
327
/* Add new method. */
328
meth = STABLE(how)->find_method(interp, how,
329
Parrot_str_new_constant(interp, "add_method"), NO_HINT);
330
cappy = Parrot_pmc_new(interp, enum_class_CallContext);
331
VTABLE_push_pmc(interp, cappy, how);
332
VTABLE_push_pmc(interp, cappy, knowhow_attr);
333
VTABLE_push_string(interp, cappy, Parrot_str_new_constant(interp, "new"));
334
VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_new)));
335
Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
336
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx);
338
/* Add name method. */
339
cappy = Parrot_pmc_new(interp, enum_class_CallContext);
340
VTABLE_push_pmc(interp, cappy, how);
341
VTABLE_push_pmc(interp, cappy, knowhow_attr);
342
VTABLE_push_string(interp, cappy, name_str);
343
VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_name)));
344
Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
345
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx);
348
meth = STABLE(knowhow)->find_method(interp, how,
349
Parrot_str_new_constant(interp, "compose"), NO_HINT);
350
cappy = Parrot_pmc_new(interp, enum_class_CallContext);
351
VTABLE_push_pmc(interp, cappy, how);
352
VTABLE_push_pmc(interp, cappy, knowhow_attr);
353
Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
354
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx);
356
/* Associate the created object with the intial core serialization
358
VTABLE_set_pmc_keyed_int(interp, sc, 2, knowhow_attr);
359
SC_PMC(knowhow_attr) = sc;
360
STABLE(knowhow_attr)->sc = sc;