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,__str__) {
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  /* Push args */
189  int argCount = argc;
190  for (int i = 0; i < argc; ++i) {
191  krk_push(argv[i]);
192  }
193 
194  if (hasKw) {
195  argCount += 3;
196  krk_push(KWARGS_VAL(KWARGS_DICT));
197  krk_push(argv[argc]);
198  krk_push(KWARGS_VAL(1));
199  }
200 
201  krk_push(krk_callDirect(self->_new, argCount));
202 
203  /* Exception here */
204  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
205 
206  if (krk_isInstanceOf(krk_peek(0), self) && likely(self->_init != NULL)) {
207  krk_push(krk_peek(0));
208  for (int i = 0; i < argc - 1; ++i) {
209  krk_push(argv[i+1]);
210  }
211 
212  if (hasKw) {
213  krk_push(KWARGS_VAL(KWARGS_DICT));
214  krk_push(argv[argc]);
215  krk_push(KWARGS_VAL(1));
216  }
217 
218  KrkValue result = krk_callDirect(self->_init, argCount);
219  if (!IS_NONE(result)) {
220  fprintf(stderr, "Warning: Non-None result returned from %s.__init__\n",
221  self->name->chars);
222  }
223  }
224 
225  return krk_pop();
226 }
227 
228 _noexport
229 void _createAndBind_type(void) {
230  KrkClass * type = ADD_BASE_CLASS(vm.baseClasses->typeClass, "type", vm.baseClasses->objectClass);
231  type->allocSize = sizeof(KrkClass);
232 
233  BIND_PROP(type,__base__);
234  BIND_PROP(type,__file__);
235  BIND_PROP(type,__name__);
236 
237  BIND_METHOD(type,__str__);
238  BIND_METHOD(type,__subclasses__);
239  BIND_METHOD(type,__getitem__);
240  BIND_METHOD(type,__call__);
241  BIND_STATICMETHOD(type,__new__);
242  krk_defineNative(&type->methods,"__repr__",FUNC_NAME(type,__str__));
243 
244  krk_finalizeClass(type);
245  KRK_DOC(type, "Obtain the object representation of the class of an object.");
246 }
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:445
Functions for dealing with garbage collection and memory allocation.
struct KrkClass KrkClass
Type object.
Type object.
Definition: object.h:189
KrkClass * krk_newClass(KrkString *name, KrkClass *base)
Create a new class object.
Definition: object.c:320
KrkString * name
Name of the class.
Definition: object.h:193
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:196
KrkObj obj
Base.
Definition: object.h:190
KrkTable methods
General attributes table.
Definition: object.h:192
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
struct KrkClass * _class
Metaclass.
Definition: object.h:191
int krk_bindMethodSuper(KrkClass *baseClass, KrkString *name, KrkClass *realClass)
Bind a method with super() semantics.
Definition: vm.c:1664
Flexible mapping type.
Definition: object.h:323
KrkTable entries
The actual table of values in the dict.
Definition: object.h:325
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
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:178
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
Definition: vm.c:194
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
Definition: table.c:169
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:189
int flags
Definition: vm.h:174
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:317
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:275
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
Definition: util.h:348
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:292
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
Definition: vm.c:763
#define vm
Convenience macro for namespacing.
Definition: vm.h:267
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:170
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:157
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:771
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:178