sys.c
1 #include <kuroko/vm.h>
2 #include <kuroko/value.h>
3 #include <kuroko/object.h>
4 #include <kuroko/util.h>
5 
6 #define KRK_VERSION_MAJOR 1
7 #define KRK_VERSION_MINOR 4
8 #define KRK_VERSION_PATCH 1
9 #define KRK_VERSION_LEVEL 0xa
10 #define KRK_VERSION_SERIAL 0x0
11 
12 #define KRK_VERSION_EXTRA_BASE "a0"
13 
14 #ifndef KRK_STATIC_ONLY
15 #define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE
16 #else
17 #define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE "-static"
18 #endif
19 
20 #define KRK_BUILD_DATE __DATE__ " at " __TIME__
21 
22 #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
23 # define KRK_BUILD_COMPILER "GCC " __VERSION__
24 #elif (defined(__clang__))
25 # define KRK_BUILD_COMPILER "clang " __clang_version__
26 #else
27 # define KRK_BUILD_COMPILER ""
28 #endif
29 
30 
31 #ifndef KRK_DISABLE_DEBUG
32 KRK_Function(set_tracing) {
33  int tracing = -1;
34  int disassembly = -1;
35 
36  if (!krk_parseArgs(
37  "|$pp", (const char *[]){"tracing","disassembly"},
38  &tracing, &disassembly)) {
39  return NONE_VAL();
40  }
41 
42 #define SET_THREAD(arg,flag) do { if (arg != -1) { if (arg) krk_currentThread.flags |= KRK_THREAD_ENABLE_ ## flag; else krk_currentThread.flags &= ~KRK_THREAD_ENABLE_ ## flag; } } while (0)
43  SET_THREAD(tracing,TRACING);
44  SET_THREAD(disassembly,DISASSEMBLY);
45 #undef SET_THREAD
46 
47  return BOOLEAN_VAL(1);
48 }
49 #else
50 KRK_Function(set_tracing) {
51  return krk_runtimeError(vm.exceptions->typeError,"Debugging is not enabled in this build.");
52 }
53 #endif
54 
55 KRK_Function(getsizeof) {
56  if (argc < 1 || !IS_OBJECT(argv[0])) return INTEGER_VAL(0);
57  size_t mySize = 0;
58  switch (AS_OBJECT(argv[0])->type) {
59  case KRK_OBJ_STRING: {
60  KrkString * self = AS_STRING(argv[0]);
61  mySize += sizeof(KrkString) + self->length + 1; /* For the UTF8 */
62  if (self->codes && self->chars != self->codes) {
63  if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) <= KRK_OBJ_FLAGS_STRING_UCS1) mySize += self->codesLength;
64  else if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS2) mySize += 2 * self->codesLength;
65  else if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS4) mySize += 4 * self->codesLength;
66  }
67  break;
68  }
69  case KRK_OBJ_CODEOBJECT: {
70  KrkCodeObject * self = (KrkCodeObject*)AS_OBJECT(argv[0]);
71  mySize += sizeof(KrkCodeObject);
72  /* Chunk size */
73  mySize += sizeof(uint8_t) * self->chunk.capacity;
74  mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
75  mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
76  /* requiredArgNames */
77  mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
78  /* keywordArgNames */
79  mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
80  /* Locals array */
81  mySize += sizeof(KrkLocalEntry) * self->localNameCount;
82  break;
83  }
84  case KRK_OBJ_NATIVE: {
85  KrkNative * self = (KrkNative*)AS_OBJECT(argv[0]);
86  mySize += sizeof(KrkNative) + strlen(self->name) + 1;
87  break;
88  }
89  case KRK_OBJ_CLOSURE: {
90  KrkClosure * self = AS_CLOSURE(argv[0]);
91  mySize += sizeof(KrkClosure) + sizeof(KrkUpvalue*) * self->function->upvalueCount;
92  break;
93  }
94  case KRK_OBJ_UPVALUE: {
95  /* It should not be possible for an upvalue to be an argument to getsizeof,
96  * but for the sake of completeness, we'll include it here... */
97  mySize += sizeof(KrkUpvalue);
98  break;
99  }
100  case KRK_OBJ_CLASS: {
101  KrkClass * self = AS_CLASS(argv[0]);
102  mySize += sizeof(KrkClass);
103  mySize += sizeof(KrkTableEntry) * self->methods.capacity;
104  mySize += sizeof(KrkTableEntry) * self->subclasses.capacity;
105  break;
106  }
107  case KRK_OBJ_INSTANCE: {
108  KrkInstance * self = AS_INSTANCE(argv[0]);
109  mySize += sizeof(KrkTableEntry) * self->fields.capacity;
110  KrkClass * type = krk_getType(argv[0]);
111  mySize += type->allocSize; /* All instance types have an allocSize set */
112 
113  /* TODO __sizeof__ */
114  if (krk_isInstanceOf(argv[0], vm.baseClasses->listClass)) {
115  mySize += sizeof(KrkValue) * AS_LIST(argv[0])->capacity;
116  } else if (krk_isInstanceOf(argv[0], vm.baseClasses->dictClass)) {
117  mySize += sizeof(KrkTableEntry) * AS_DICT(argv[0])->capacity;
118  }
119  break;
120  }
121  case KRK_OBJ_BOUND_METHOD: {
122  mySize += sizeof(KrkBoundMethod);
123  break;
124  }
125  case KRK_OBJ_TUPLE: {
126  KrkTuple * self = AS_TUPLE(argv[0]);
127  mySize += sizeof(KrkTuple) + sizeof(KrkValue) * self->values.capacity;
128  break;
129  }
130  case KRK_OBJ_BYTES: {
131  KrkBytes * self = AS_BYTES(argv[0]);
132  mySize += sizeof(KrkBytes) + self->length;
133  break;
134  }
135  default: break;
136  }
137  return INTEGER_VAL(mySize);
138 }
139 
140 KRK_Function(set_clean_output) {
141  if (!argc || (IS_BOOLEAN(argv[0]) && AS_BOOLEAN(argv[0]))) {
142  vm.globalFlags |= KRK_GLOBAL_CLEAN_OUTPUT;
143  } else {
144  vm.globalFlags &= ~KRK_GLOBAL_CLEAN_OUTPUT;
145  }
146  return NONE_VAL();
147 }
148 
149 KRK_Function(importmodule) {
150  FUNCTION_TAKES_EXACTLY(1);
151  if (!IS_STRING(argv[0])) return TYPE_ERROR(str,argv[0]);
152  if (!krk_doRecursiveModuleLoad(AS_STRING(argv[0]))) return NONE_VAL(); /* ImportError already raised */
153  return krk_pop();
154 }
155 
156 KRK_Function(modules) {
157  FUNCTION_TAKES_NONE();
158  KrkValue moduleList = krk_list_of(0,NULL,0);
159  krk_push(moduleList);
160  for (size_t i = 0; i < vm.modules.capacity; ++i) {
161  KrkTableEntry * entry = &vm.modules.entries[i];
162  if (IS_KWARGS(entry->key)) continue;
163  krk_writeValueArray(AS_LIST(moduleList), entry->key);
164  }
165  return krk_pop();
166 }
167 
168 KRK_Function(unload) {
169  FUNCTION_TAKES_EXACTLY(1);
170  if (!IS_STRING(argv[0])) return TYPE_ERROR(str,argv[0]);
171  if (!krk_tableDelete(&vm.modules, argv[0])) {
172  return krk_runtimeError(vm.exceptions->keyError, "Module is not loaded.");
173  }
174  return NONE_VAL();
175 }
176 
177 KRK_Function(inspect_value) {
178  FUNCTION_TAKES_EXACTLY(1);
179  return OBJECT_VAL(krk_newBytes(sizeof(KrkValue),(uint8_t*)&argv[0]));
180 }
181 
182 KRK_Function(members) {
183  KrkValue val;
184  if (!krk_parseArgs("V", (const char*[]){"obj"}, &val)) return NONE_VAL();
185 
186  KrkValue myDict = krk_dict_of(0,NULL,0);
187  krk_push(myDict);
188 
189  KrkTable * src = NULL;
190 
191  if (IS_INSTANCE(val) || IS_CLASS(val)) {
192  src = &AS_INSTANCE(val)->fields;
193  } else if (IS_CLOSURE(val)) {
194  src = &AS_CLOSURE(val)->fields;
195  }
196 
197  if (src) {
198  krk_tableAddAll(src, AS_DICT(myDict));
199  }
200 
201  return krk_pop();
202 }
203 
212  vm.system = krk_newInstance(vm.baseClasses->moduleClass);
213  krk_attachNamedObject(&vm.modules, "kuroko", (KrkObj*)vm.system);
214  krk_attachNamedObject(&vm.system->fields, "__name__", (KrkObj*)S("kuroko"));
215  krk_attachNamedValue(&vm.system->fields, "__file__", NONE_VAL()); /* (built-in) */
216  KRK_DOC(vm.system, "@brief System module.");
217 #define STR_(x) #x
218 #define STR(x) STR_(x)
219  krk_attachNamedObject(&vm.system->fields, "version",
220  (KrkObj*)S(STR(KRK_VERSION_MAJOR) "." STR(KRK_VERSION_MINOR) "." STR(KRK_VERSION_PATCH) KRK_VERSION_EXTRA));
221  krk_attachNamedObject(&vm.system->fields, "buildenv", (KrkObj*)S(KRK_BUILD_COMPILER));
222  krk_attachNamedObject(&vm.system->fields, "builddate", (KrkObj*)S(KRK_BUILD_DATE));
223  krk_attachNamedValue(&vm.system->fields, "hexversion",
224  INTEGER_VAL((KRK_VERSION_MAJOR << 24) | (KRK_VERSION_MINOR << 16) | (KRK_VERSION_PATCH << 8) | (KRK_VERSION_LEVEL << 4) | (KRK_VERSION_SERIAL)));
225 
226  KRK_DOC(BIND_FUNC(vm.system,getsizeof),
227  "@brief Calculate the approximate size of an object in bytes.\n"
228  "@arguments value\n\n"
229  "@param value Value to examine.");
230  KRK_DOC(BIND_FUNC(vm.system,set_clean_output),
231  "@brief Disables terminal escapes in some output from the VM.\n"
232  "@arguments clean=True\n\n"
233  "@param clean Whether to remove escapes.");
234  KRK_DOC(BIND_FUNC(vm.system,set_tracing),
235  "@brief Toggle debugging modes.\n"
236  "@arguments tracing=None,disassembly=None\n\n"
237  "Enables or disables tracing options for the current thread.\n\n"
238  "@param tracing Enables instruction tracing.\n"
239  "@param disassembly Prints bytecode disassembly after compilation.");
240  KRK_DOC(BIND_FUNC(vm.system,importmodule),
241  "@brief Import a module by string name\n"
242  "@arguments module\n\n"
243  "Imports the dot-separated module @p module as if it were imported by the @c import statement and returns the resulting module object.\n\n"
244  "@param module A string with a dot-separated package or module name");
245  KRK_DOC(BIND_FUNC(vm.system,modules),
246  "Get the list of valid names from the module table");
247  KRK_DOC(BIND_FUNC(vm.system,unload),
248  "Removes a module from the module table. It is not necessarily garbage collected if other references to it exist.");
249  KRK_DOC(BIND_FUNC(vm.system,inspect_value),
250  "Obtain the memory representation of a stack value.");
251  KRK_DOC(BIND_FUNC(vm.system,members),
252  "Obtain a copy of a dict of the direct members of an object.");
253  krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass);
254  krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
255  KrkValue module_paths = krk_list_of(0,NULL,0);
256  krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths);
257  krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(S("./")));
258 #ifndef KRK_NO_FILESYSTEM
259  if (vm.binpath) {
260  krk_attachNamedObject(&vm.system->fields, "executable_path", (KrkObj*)krk_copyString(vm.binpath, strlen(vm.binpath)));
261  char * dir = strdup(vm.binpath);
262 #ifndef _WIN32
263  char * slash = strrchr(dir,'/');
264  if (slash) *slash = '\0';
265  if (strstr(dir,"/bin") == (dir + strlen(dir) - 4)) {
266  slash = strrchr(dir,'/');
267  if (slash) *slash = '\0';
268  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s/lib/kuroko/", dir));
269  } else {
270  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s/modules/", dir));
271  }
272 #else
273  char * backslash = strrchr(dir,'\\');
274  if (backslash) *backslash = '\0';
275  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s\\modules\\", dir));
276 #endif
277  free(dir);
278  }
279 #endif
280 }
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:445
Struct definitions for core object types.
struct KrkClass KrkClass
Type object.
struct KrkString KrkString
Immutable sequence of Unicode codepoints.
struct KrkUpvalue KrkUpvalue
Storage for values referenced from nested functions.
A function that has been attached to an object to serve as a method.
Definition: object.h:269
Immutable sequence of bytes.
Definition: object.h:105
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
Definition: object.c:363
Type object.
Definition: object.h:189
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:196
Function object.
Definition: object.h:169
Code object.
Definition: object.h:144
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
Definition: obj_dict.c:11
An object of a class.
Definition: object.h:255
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:339
Map entry of instruction offsets to line numbers.
Definition: chunk.h:19
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
Metadata on a local variable name in a function.
Definition: object.h:129
Managed binding to a C function.
Definition: object.h:283
The most basic object type.
Definition: object.h:41
Immutable sequence of Unicode codepoints.
Definition: object.h:93
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:221
One (key,value) pair in a table.
Definition: table.h:20
Simple hash table of arbitrary keys to values.
Definition: table.h:28
int krk_tableDelete(KrkTable *table, KrkValue key)
Remove a key from a hash table.
Definition: table.c:208
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:839
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:825
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
Definition: table.c:169
Immutable sequence of arbitrary values.
Definition: object.h:297
Storage for values referenced from nested functions.
Definition: object.h:115
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.
#define vm
Convenience macro for namespacing.
Definition: vm.h:267
int krk_doRecursiveModuleLoad(KrkString *name)
Load a module by a dotted name.
Definition: vm.c:1610
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:170
void krk_module_init_kuroko(void)
Initialize the built-in 'kuroko' module.
Definition: sys.c:204
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:157