/
class.cpp
202 lines (151 loc) · 6.25 KB
/
class.cpp
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
#include "builtin/class.hpp"
#include "builtin/module.hpp"
#include "builtin/symbol.hpp"
#include "helpers.hpp"
#include "exception_point.hpp"
#include "on_stack.hpp"
#include "capi/capi.hpp"
#include "capi/18/include/ruby.h"
#include <string.h>
using namespace rubinius;
using namespace rubinius::capi;
extern "C" {
VALUE rb_class_new_instance(int arg_count, VALUE* args, VALUE class_handle) {
return rb_funcall2(class_handle, rb_intern("new"), arg_count, args);
}
VALUE rb_class_of(VALUE object_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Class* class_object = env->get_object(object_handle)->class_object(env->state());
return env->get_handle(class_object);
}
// MUST return the immediate object in the class field, not the real class!
VALUE CLASS_OF(VALUE object_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Class* class_object = env->get_object(object_handle)->lookup_begin(env->state());
return env->get_handle(class_object);
}
VALUE rb_class_name(VALUE class_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Class* class_object = c_as<Class>(env->get_object(class_handle));
return env->get_handle(class_object->get_name(env->state()));
}
VALUE rb_class_inherited(VALUE super_handle, VALUE class_handle)
{
if(!super_handle) super_handle = rb_cObject;
return rb_funcall(super_handle, rb_intern("inherited"), 1, class_handle);
}
VALUE rb_class_new(VALUE super_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
if(super_handle == rb_cClass) {
rb_raise(rb_eTypeError, "can't make subclass of Class");
}
if(try_as<SingletonClass>(env->get_object(super_handle))) {
rb_raise(rb_eTypeError, "can't make subclass of virtual class");
}
Class* klass = Class::create(env->state(), c_as<Class>(env->get_object(super_handle)));
return env->get_handle(klass);
}
VALUE rb_path2class(const char* path) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Module* mod = env->state()->vm()->shared.globals.object.get();
Object* val = 0;
char* pathd = strdup(path);
char* ptr = pathd;
char* context;
char* name;
bool found = false;
while((name = strtok_r(ptr, ":", &context))) {
ptr = NULL;
val = mod->get_const(env->state(), env->state()->symbol(name), &found);
if(!found) {
free(pathd);
rb_raise(rb_eArgError, "undefined class or module %s", path);
}
if(!(mod = try_as<Module>(val))) {
free(pathd);
capi_raise_type_error(Module::type, val);
}
}
free(pathd);
return env->get_handle(mod);
}
VALUE rb_cv_get(VALUE module_handle, const char* name) {
return rb_cvar_get(module_handle, rb_intern(name));
}
VALUE rb_cv_set(VALUE module_handle, const char* name, VALUE value) {
return rb_cvar_set(module_handle, rb_intern(name), value, 0);
}
VALUE rb_cvar_defined(VALUE module_handle, ID name) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
if (((Symbol *)name)->is_cvar_p(env->state())->true_p()) {
return rb_funcall(module_handle, rb_intern("class_variable_defined?"),
1, name);
} else {
return rb_funcall(module_handle, rb_intern("instance_variable_defined?"),
1, name);
}
}
VALUE rb_cvar_get(VALUE module_handle, ID name) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
return rb_funcall(module_handle, rb_intern("class_variable_get"),
1,
env->get_handle(prefixed_by(env->state(), "@@", 2, name)));
}
VALUE rb_cvar_set_internal(VALUE module_handle, ID name, VALUE value) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
return rb_funcall(module_handle, rb_intern("class_variable_set"),
2,
env->get_handle(prefixed_by(env->state(), "@@", 2, name)),
value);
}
VALUE rb_define_class(const char* name, VALUE superclass_handle) {
return rb_define_class_under(rb_cObject, name, superclass_handle);
}
void rb_define_class_variable(VALUE klass, const char* name, VALUE val) {
ID id = rb_intern(name);
rb_cvar_set(klass, id, val, 0);
}
/** @note Shares code with rb_define_module_under, change there too. --rue */
VALUE rb_define_class_under(VALUE outer, const char* name, VALUE super) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Module* module = c_as<Module>(env->get_object(outer));
Class* superclass = c_as<Class>(env->get_object(super ? super : rb_cObject));
Symbol* constant = env->state()->symbol(name);
bool created = false;
LEAVE_CAPI(env->state());
Class* opened_class = NULL;
// Run in a block so OnStack is properly deallocated before we
// might do a longjmp because of an exception.
{
GCTokenImpl gct;
OnStack<3> os(env->state(), module, superclass, constant);
opened_class = rubinius::Helpers::open_class(env->state(), gct,
env->current_call_frame(), module, superclass, constant, &created);
}
// The call above could have triggered an Autoload resolve, which may
// raise an exception, so we have to check the value returned.
if(!opened_class) env->current_ep()->return_to(env);
// We need to grab the handle before entering back into C-API
// code. The problem otherwise can be that the GC runs and
// the opened_class is GC'ed.
VALUE klass = env->get_handle(opened_class);
ENTER_CAPI(env->state());
if(super) rb_funcall(super, rb_intern("inherited"), 1, klass);
return klass;
}
void rb_attr(VALUE klass, ID id, int read, int write, int ex) {
// TODO don't ignore ex.
if(read) {
rb_funcall(klass, rb_intern("attr_reader"), 1, ID2SYM(id));
}
if(write) {
rb_funcall(klass, rb_intern("attr_writer"), 1, ID2SYM(id));
}
}
/** @todo Should this be a global handle? Surely not.. --rue */
VALUE rb_singleton_class(VALUE object_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Class* sc = env->get_object(object_handle)->singleton_class(env->state());
return env->get_handle(sc);
}
}