obj_base.c
1 #include <string.h>
2 #include <kuroko/vm.h>
3 #include <kuroko/value.h>
4 #include <kuroko/memory.h>
5 #include <kuroko/util.h>
6 
7 #define CURRENT_NAME self
8 
9 #define IS_type(o) (IS_CLASS(o))
10 #define AS_type(o) (AS_CLASS(o))
11 
12 #define CURRENT_CTYPE KrkClass *
13 
14 static void _callSetName(KrkClass * _class) {
15  KrkValue setnames = krk_list_of(0,NULL,0);
16  krk_push(setnames);
17  extern FUNC_SIG(list,append);
18 
19  /* The semantics of this require that we first collect all of the relevant items... */
20  for (size_t i = 0; i < _class->methods.capacity; ++i) {
21  KrkTableEntry * entry = &_class->methods.entries[i];
22  if (!IS_KWARGS(entry->key)) {
23  KrkClass * type = krk_getType(entry->value);
24  if (type->_set_name) {
25  FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->key},0);
26  FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->value},0);
27  }
28  }
29  }
30 
31  /* Then call __set_name__ on them */
32  for (size_t i = 0; i < AS_LIST(setnames)->count; i += 2) {
33  KrkValue name = AS_LIST(setnames)->values[i];
34  KrkValue value = AS_LIST(setnames)->values[i+1];
35  KrkClass * type = krk_getType(value);
36  if (type->_set_name) {
37  krk_push(value);
38  krk_push(OBJECT_VAL(_class));
39  krk_push(name);
40  krk_callDirect(type->_set_name, 3);
41 
42  /* If any of these raises an exception, bail; CPython raises
43  * an outer exception, setting the cause, but I'm being lazy
44  * at the moment... */
45  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
46  break;
47  }
48  }
49  }
50 
51  /* List used to store name+value pairs */
52  krk_pop();
53 }
54 
55 KRK_StaticMethod(type,__new__) {
56  KrkClass * metaclass;
57  KrkString * name;
58  KrkClass * base;
59  KrkDict * nspace;
60 
61  if (!krk_parseArgs("O!O!O!O!~:type",
62  (const char*[]){"cls","name","base","namespace"},
63  vm.baseClasses->typeClass, &metaclass,
64  vm.baseClasses->strClass, &name,
65  vm.baseClasses->typeClass, &base,
66  vm.baseClasses->dictClass, &nspace)) {
67  return NONE_VAL();
68  }
69 
70  if (base->obj.flags & KRK_OBJ_FLAGS_NO_INHERIT) {
71  return krk_runtimeError(vm.exceptions->typeError, "'%S' can not be subclassed", base->name);
72  }
73 
74  /* Now make a class */
75  KrkClass * _class = krk_newClass(name, base);
76  krk_push(OBJECT_VAL(_class));
77  _class->_class = metaclass;
78 
79  /* Now copy the values over */
80  krk_tableAddAll(&nspace->entries, &_class->methods);
81 
82  KrkValue tmp;
83 
84  if (krk_tableGet_fast(&_class->methods, S("__class_getitem__"), &tmp) && IS_CLOSURE(tmp)) {
85  AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
86  }
87 
88  if (krk_tableGet_fast(&_class->methods, S("__init_subclass__"), &tmp) && IS_CLOSURE(tmp)) {
89  AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
90  }
91 
92  if (krk_tableGet_fast(&_class->methods, S("__new__"), &tmp) && IS_CLOSURE(tmp)) {
93  AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
94  }
95 
96  krk_finalizeClass(_class);
97  _callSetName(_class);
98 
99  /* Call super().__init_subclass__ */
100  krk_push(NONE_VAL());
101  if (!krk_bindMethodSuper(base,S("__init_subclass__"),_class)) {
102  krk_pop(); /* none */
103  } else {
104  if (hasKw) {
105  krk_push(KWARGS_VAL(KWARGS_DICT));
106  krk_push(argv[argc]);
107  krk_push(KWARGS_VAL(1));
108  krk_callStack(3);
109  } else {
110  krk_callStack(0);
111  }
112  }
113 
114  return krk_pop();
115 }
116 
117 KRK_Method(type,__base__) {
118  if (argc > 1) return krk_runtimeError(vm.exceptions->typeError, "__base__ can not be reassigned");
119  return self->base ? OBJECT_VAL(self->base) : NONE_VAL();
120 }
121 
122 KRK_Method(type,__name__) {
123  if (argc > 1) {
124  if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
125  self->name = AS_STRING(argv[1]);
126  }
127  return self->name ? OBJECT_VAL(self->name) : NONE_VAL();
128 }
129 
130 KRK_Method(type,__file__) {
131  if (argc > 1) {
132  if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
133  self->filename = AS_STRING(argv[1]);
134  }
135  return self->filename ? OBJECT_VAL(self->filename) : NONE_VAL();
136 }
137 
138 KRK_Method(type,__repr__) {
139  /* Determine if this class has a module */
140  KrkValue module = NONE_VAL();
141  krk_tableGet(&self->methods, OBJECT_VAL(S("__module__")), &module);
142 
143  KrkValue qualname = NONE_VAL();
144  krk_tableGet(&self->methods, OBJECT_VAL(S("__qualname__")), &qualname);
145  KrkString * name = IS_STRING(qualname) ? AS_STRING(qualname) : self->name;
146 
147  int includeModule = !(IS_NONE(module) || (IS_STRING(module) && AS_STRING(module) == S("builtins")));
148 
149  return krk_stringFromFormat("<class '%s%s%S'>",
150  includeModule ? AS_CSTRING(module) : "",
151  includeModule ? "." : "",
152  name);
153 }
154 
155 KRK_Method(type,__subclasses__) {
156  KrkValue myList = krk_list_of(0,NULL,0);
157  krk_push(myList);
158 
159  for (size_t i = 0; i < self->subclasses.capacity; ++i) {
160  KrkTableEntry * entry = &self->subclasses.entries[i];
161  if (IS_KWARGS(entry->key)) continue;
162  krk_writeValueArray(AS_LIST(myList), entry->key);
163  }
164 
165  return krk_pop();
166 }
167 
168 KRK_Method(type,__getitem__) {
169  if (self->_classgetitem && argc == 2) {
170  krk_push(argv[0]);
171  krk_push(argv[1]);
172  return krk_callDirect(self->_classgetitem, 2);
173  }
174  return krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not subscriptable", "type");
175 }
176 
177 KRK_Method(type,__call__) {
178  if (self == vm.baseClasses->typeClass) {
179  if (argc == 2) {
180  return OBJECT_VAL(krk_getType(argv[1]));
181  }
182  }
183 
184  if (!self->_new) {
185  return krk_runtimeError(vm.exceptions->typeError, "%S() can not be built", self->name);
186  }
187 
188  KrkValue result;
189  if (self->_new->type == KRK_OBJ_NATIVE) {
190  /* Fast call to native __new__ function. */
191  result = ((KrkNative*)self->_new)->function(argc,argv,hasKw);
192  } else {
193  /* Slow call: Put arguments back on the stack with kwargs call format */
194  int argCount = argc;
195  for (int i = 0; i < argc; ++i) {
196  krk_push(argv[i]);
197  }
198 
199  if (hasKw) {
200  argCount += 3;
201  krk_push(KWARGS_VAL(KWARGS_DICT));
202  krk_push(argv[argc]);
203  krk_push(KWARGS_VAL(1));
204  }
205 
206  result = krk_callDirect(self->_new, argCount);
207  }
208 
209  /* If an exception happened in __new__, don't try to call __init__ even if the conditions would be right. */
210  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
211 
212  if (self->_init != KRK_BASE_CLASS(object)->_init && self->_init != NULL && krk_isInstanceOf(result, self)) {
213  /* Because we have to swap the class for the instance here, we can't do a fast call even
214  * if __init__ is a native function, so we're stuck with the slow approach... */
215  krk_push(result); /* once for safe keeping */
216  krk_push(result); /* once as an argument */
217  int argCount = argc;
218  for (int i = 0; i < argc - 1; ++i) {
219  krk_push(argv[i+1]);
220  }
221 
222  if (hasKw) {
223  argCount += 3;
224  krk_push(KWARGS_VAL(KWARGS_DICT));
225  krk_push(argv[argc]);
226  krk_push(KWARGS_VAL(1));
227  }
228 
229  KrkValue result = krk_callDirect(self->_init, argCount);
230  if (!IS_NONE(result)) {
231  fprintf(stderr, "Warning: Non-None result returned from %s.__init__\n",
232  self->name->chars);
233  }
234  return krk_pop();
235  }
236 
237  return result;
238 }
239 
240 _noexport
241 void _createAndBind_type(void) {
242  KrkClass * type = ADD_BASE_CLASS(vm.baseClasses->typeClass, "type", vm.baseClasses->objectClass);
243  type->allocSize = sizeof(KrkClass);
244 
245  BIND_PROP(type,__base__);
246  BIND_PROP(type,__file__);
247  BIND_PROP(type,__name__);
248 
249  BIND_METHOD(type,__repr__);
250  BIND_METHOD(type,__subclasses__);
251  BIND_METHOD(type,__getitem__);
252  BIND_METHOD(type,__call__);
253  BIND_STATICMETHOD(type,__new__);
254 
255  krk_finalizeClass(type);
256  KRK_DOC(type, "Obtain the object representation of the class of an object.");
257 }
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
Functions for dealing with garbage collection and memory allocation.
struct KrkClass KrkClass
Type object.
Type object.
Definition: object.h:215
KrkClass * krk_newClass(KrkString *name, KrkClass *base)
Create a new class object.
Definition: object.c:324
KrkString * name
Name of the class.
Definition: object.h:219
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:222
KrkObj obj
Base.
Definition: object.h:216
KrkTable methods
General attributes table.
Definition: object.h:218
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
struct KrkClass * _class
Metaclass.
Definition: object.h:217
int krk_bindMethodSuper(KrkClass *baseClass, KrkString *name, KrkClass *realClass)
Bind a method with super() semantics.
Definition: vm.c:1626
Flexible mapping type.
Definition: object.h:349
KrkTable entries
The actual table of values in the dict.
Definition: object.h:351
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
Managed binding to a C function.
Definition: object.h:309
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Immutable sequence of Unicode codepoints.
Definition: object.h:93
One (key,value) pair in a table.
Definition: table.h:20
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:211
KrkTableEntry * entries
Definition: table.h:32
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
Definition: table.c:202
int krk_tableGet_fast(KrkTable *table, struct KrkString *str, KrkValue *value)
Obtain the value associated with a string key in a table.
Definition: table.c:219
size_t capacity
Definition: table.h:30
int flags
Definition: vm.h:165
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
Stack reference or primative value.
int krk_isInstanceOf(KrkValue obj, const KrkClass *type)
Determine if a class is an instance or subclass of a given type.
Definition: vm.c:282
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:240
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
Definition: util.h:360
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:304
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
Definition: vm.c:732
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:740