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 5
8 #define KRK_VERSION_PATCH 0
9 #define KRK_VERSION_LEVEL 0xa
10 #define KRK_VERSION_SERIAL 0x1
11 
12 #define KRK_VERSION_EXTRA_BASE "a1"
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 #elif (defined(_MSC_VER) && !defined(__clang__))
27 # define KRK_ARG_STR(str) #str
28 # define KRK_ARG_LOL(s) KRK_ARG_STR(s)
29 # define KRK_BUILD_COMPILER "msvc " KRK_ARG_LOL(_MSC_FULL_VER)
30 #else
31 # define KRK_BUILD_COMPILER ""
32 #endif
33 
34 
35 #ifndef KRK_DISABLE_DEBUG
36 KRK_Function(set_tracing) {
37  int tracing = -1;
38  int disassembly = -1;
39 
40  if (!krk_parseArgs(
41  "|$pp", (const char *[]){"tracing","disassembly"},
42  &tracing, &disassembly)) {
43  return NONE_VAL();
44  }
45 
46 #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)
47  SET_THREAD(tracing,TRACING);
48  SET_THREAD(disassembly,DISASSEMBLY);
49 #undef SET_THREAD
50 
51  return BOOLEAN_VAL(1);
52 }
53 #else
54 KRK_Function(set_tracing) {
55  return krk_runtimeError(vm.exceptions->typeError,"Debugging is not enabled in this build.");
56 }
57 #endif
58 
59 KRK_Function(getsizeof) {
60  if (argc < 1 || !IS_OBJECT(argv[0])) return INTEGER_VAL(0);
61  size_t mySize = 0;
62  switch (AS_OBJECT(argv[0])->type) {
63  case KRK_OBJ_STRING: {
64  KrkString * self = AS_STRING(argv[0]);
65  mySize += sizeof(KrkString) + self->length + 1; /* For the UTF8 */
66  if (self->codes && self->chars != self->codes) {
67  if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) <= KRK_OBJ_FLAGS_STRING_UCS1) mySize += self->codesLength;
68  else if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS2) mySize += 2 * self->codesLength;
69  else if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS4) mySize += 4 * self->codesLength;
70  }
71  break;
72  }
73  case KRK_OBJ_CODEOBJECT: {
74  KrkCodeObject * self = (KrkCodeObject*)AS_OBJECT(argv[0]);
75  mySize += sizeof(KrkCodeObject);
76  /* Chunk size */
77  mySize += sizeof(uint8_t) * self->chunk.capacity;
78  mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
79  mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
80  mySize += sizeof(KrkExpressionsMap) * self->expressionsCapacity;
81  /* requiredArgNames */
82  mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
83  /* keywordArgNames */
84  mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
85  /* Locals array */
86  mySize += sizeof(KrkLocalEntry) * self->localNameCount;
87  /* Overlong jumps */
88  mySize += sizeof(KrkOverlongJump) * self->overlongJumpsCapacity;
89  break;
90  }
91  case KRK_OBJ_NATIVE: {
92  KrkNative * self = (KrkNative*)AS_OBJECT(argv[0]);
93  mySize += sizeof(KrkNative) + strlen(self->name) + 1;
94  break;
95  }
96  case KRK_OBJ_CLOSURE: {
97  KrkClosure * self = AS_CLOSURE(argv[0]);
98  mySize += sizeof(KrkClosure) + sizeof(KrkUpvalue*) * self->function->upvalueCount;
99  break;
100  }
101  case KRK_OBJ_UPVALUE: {
102  /* It should not be possible for an upvalue to be an argument to getsizeof,
103  * but for the sake of completeness, we'll include it here... */
104  mySize += sizeof(KrkUpvalue);
105  break;
106  }
107  case KRK_OBJ_CLASS: {
108  KrkClass * self = AS_CLASS(argv[0]);
109  mySize += sizeof(KrkClass);
110  mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->methods.capacity;
111  mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->subclasses.capacity;
112  break;
113  }
114  case KRK_OBJ_INSTANCE: {
115  KrkInstance * self = AS_INSTANCE(argv[0]);
116  mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->fields.capacity;
117  KrkClass * type = krk_getType(argv[0]);
118  mySize += type->allocSize; /* All instance types have an allocSize set */
119 
120  /* TODO __sizeof__ */
121  if (krk_isInstanceOf(argv[0], vm.baseClasses->listClass)) {
122  mySize += sizeof(KrkValue) * AS_LIST(argv[0])->capacity;
123  } else if (krk_isInstanceOf(argv[0], vm.baseClasses->dictClass)) {
124  mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * AS_DICT(argv[0])->capacity;
125  }
126  break;
127  }
128  case KRK_OBJ_BOUND_METHOD: {
129  mySize += sizeof(KrkBoundMethod);
130  break;
131  }
132  case KRK_OBJ_TUPLE: {
133  KrkTuple * self = AS_TUPLE(argv[0]);
134  mySize += sizeof(KrkTuple) + sizeof(KrkValue) * self->values.capacity;
135  break;
136  }
137  case KRK_OBJ_BYTES: {
138  KrkBytes * self = AS_BYTES(argv[0]);
139  mySize += sizeof(KrkBytes) + self->length;
140  break;
141  }
142  default: break;
143  }
144  return INTEGER_VAL(mySize);
145 }
146 
147 KRK_Function(set_clean_output) {
148  if (!argc || (IS_BOOLEAN(argv[0]) && AS_BOOLEAN(argv[0]))) {
149  vm.globalFlags |= KRK_GLOBAL_CLEAN_OUTPUT;
150  } else {
151  vm.globalFlags &= ~KRK_GLOBAL_CLEAN_OUTPUT;
152  }
153  return NONE_VAL();
154 }
155 
156 KRK_Function(importmodule) {
157  FUNCTION_TAKES_EXACTLY(1);
158  if (!IS_STRING(argv[0])) return TYPE_ERROR(str,argv[0]);
159  if (!krk_doRecursiveModuleLoad(AS_STRING(argv[0]))) return NONE_VAL(); /* ImportError already raised */
160  return krk_pop();
161 }
162 
163 KRK_Function(modules) {
164  FUNCTION_TAKES_NONE();
165  KrkValue moduleList = krk_list_of(0,NULL,0);
166  krk_push(moduleList);
167  for (size_t i = 0; i < vm.modules.capacity; ++i) {
168  KrkTableEntry * entry = &vm.modules.entries[i];
169  if (IS_KWARGS(entry->key)) continue;
170  krk_writeValueArray(AS_LIST(moduleList), entry->key);
171  }
172  return krk_pop();
173 }
174 
175 KRK_Function(unload) {
176  FUNCTION_TAKES_EXACTLY(1);
177  if (!IS_STRING(argv[0])) return TYPE_ERROR(str,argv[0]);
178  if (!krk_tableDelete(&vm.modules, argv[0])) {
179  return krk_runtimeError(vm.exceptions->keyError, "Module is not loaded.");
180  }
181  return NONE_VAL();
182 }
183 
184 KRK_Function(inspect_value) {
185  FUNCTION_TAKES_EXACTLY(1);
186  return OBJECT_VAL(krk_newBytes(sizeof(KrkValue),(uint8_t*)&argv[0]));
187 }
188 
189 KRK_Function(members) {
190  KrkValue val;
191  if (!krk_parseArgs("V", (const char*[]){"obj"}, &val)) return NONE_VAL();
192 
193  KrkValue myDict = krk_dict_of(0,NULL,0);
194  krk_push(myDict);
195 
196  KrkTable * src = NULL;
197 
198  if (IS_INSTANCE(val) || IS_CLASS(val)) {
199  src = &AS_INSTANCE(val)->fields;
200  } else if (IS_CLOSURE(val)) {
201  src = &AS_CLOSURE(val)->fields;
202  }
203 
204  if (src) {
205  krk_tableAddAll(src, AS_DICT(myDict));
206  }
207 
208  return krk_pop();
209 }
210 
211 KRK_Function(set_recursion_depth) {
212  unsigned int maxdepth;
213  int quiet = 0;
214  if (!krk_parseArgs("I|p",(const char*[]){"maxdepth","quiet"},&maxdepth,&quiet)) return NONE_VAL();
215  if (krk_currentThread.exitOnFrame != 0) {
216  if (quiet) return BOOLEAN_VAL(0);
217  return krk_runtimeError(vm.exceptions->valueError, "Can not change recursion depth in this context.");
218  }
220  return BOOLEAN_VAL(1);
221 }
222 
223 KRK_Function(get_recursion_depth) {
224  return INTEGER_VAL(krk_currentThread.maximumCallDepth);
225 }
226 
235  vm.system = krk_newInstance(vm.baseClasses->moduleClass);
236  krk_attachNamedObject(&vm.modules, "kuroko", (KrkObj*)vm.system);
237  krk_attachNamedObject(&vm.system->fields, "__name__", (KrkObj*)S("kuroko"));
238  krk_attachNamedValue(&vm.system->fields, "__file__", NONE_VAL()); /* (built-in) */
239  KRK_DOC(vm.system, "@brief System module.");
240 #define STR_(x) #x
241 #define STR(x) STR_(x)
242  krk_attachNamedObject(&vm.system->fields, "version",
243  (KrkObj*)S(STR(KRK_VERSION_MAJOR) "." STR(KRK_VERSION_MINOR) "." STR(KRK_VERSION_PATCH) KRK_VERSION_EXTRA));
244  krk_attachNamedObject(&vm.system->fields, "buildenv", (KrkObj*)S(KRK_BUILD_COMPILER));
245  krk_attachNamedObject(&vm.system->fields, "builddate", (KrkObj*)S(KRK_BUILD_DATE));
246  krk_attachNamedValue(&vm.system->fields, "hexversion",
247  INTEGER_VAL((KRK_VERSION_MAJOR << 24) | (KRK_VERSION_MINOR << 16) | (KRK_VERSION_PATCH << 8) | (KRK_VERSION_LEVEL << 4) | (KRK_VERSION_SERIAL)));
248 
249  KRK_DOC(BIND_FUNC(vm.system,getsizeof),
250  "@brief Calculate the approximate size of an object in bytes.\n"
251  "@arguments value\n\n"
252  "@param value Value to examine.");
253  KRK_DOC(BIND_FUNC(vm.system,set_clean_output),
254  "@brief Disables terminal escapes in some output from the VM.\n"
255  "@arguments clean=True\n\n"
256  "@param clean Whether to remove escapes.");
257  KRK_DOC(BIND_FUNC(vm.system,set_tracing),
258  "@brief Toggle debugging modes.\n"
259  "@arguments tracing=None,disassembly=None\n\n"
260  "Enables or disables tracing options for the current thread.\n\n"
261  "@param tracing Enables instruction tracing.\n"
262  "@param disassembly Prints bytecode disassembly after compilation.");
263  KRK_DOC(BIND_FUNC(vm.system,importmodule),
264  "@brief Import a module by string name\n"
265  "@arguments module\n\n"
266  "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"
267  "@param module A string with a dot-separated package or module name");
268  KRK_DOC(BIND_FUNC(vm.system,modules),
269  "Get the list of valid names from the module table");
270  KRK_DOC(BIND_FUNC(vm.system,unload),
271  "Removes a module from the module table. It is not necessarily garbage collected if other references to it exist.");
272  KRK_DOC(BIND_FUNC(vm.system,inspect_value),
273  "Obtain the memory representation of a stack value.");
274  KRK_DOC(BIND_FUNC(vm.system,members),
275  "Obtain a copy of a dict of the direct members of an object.");
276  KRK_DOC(BIND_FUNC(vm.system,set_recursion_depth),
277  "Change the maximum recursion depth of the current thread if possible.");
278  KRK_DOC(BIND_FUNC(vm.system,get_recursion_depth),
279  "Examine the maximum recursion depth of the current thread.");
280  krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass);
281  krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(KRK_PATH_SEP));
282  KrkValue module_paths = krk_list_of(0,NULL,0);
283  krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths);
284  krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(S("./")));
285 #ifndef KRK_NO_FILESYSTEM
286  if (vm.binpath) {
287  krk_attachNamedObject(&vm.system->fields, "executable_path", (KrkObj*)krk_copyString(vm.binpath, strlen(vm.binpath)));
288  char * dir = strdup(vm.binpath);
289 #ifndef _WIN32
290  char * slash = strrchr(dir,'/');
291  if (slash) *slash = '\0';
292  if (strstr(dir,"/bin") == (dir + strlen(dir) - 4)) {
293  slash = strrchr(dir,'/');
294  if (slash) *slash = '\0';
295  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s/lib/kuroko/", dir));
296  } else {
297  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s/modules/", dir));
298  }
299 #else
300  char * backslash = strrchr(dir,'\\');
301  if (backslash) *backslash = '\0';
302  krk_writeValueArray(AS_LIST(module_paths), krk_stringFromFormat("%s\\modules\\", dir));
303 #endif
304  free(dir);
305  }
306 #endif
307 }
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
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:295
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:367
Type object.
Definition: object.h:215
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:222
Function object.
Definition: object.h:195
Code object.
Definition: object.h:163
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
Definition: obj_dict.c:19
Map entry of opcode offsets to expressions spans.
Definition: object.h:141
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
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:309
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:224
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:238
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
Definition: table.c:202
unsigned int maximumCallDepth
Definition: vm.h:166
ssize_t exitOnFrame
Definition: vm.h:161
Immutable sequence of arbitrary values.
Definition: object.h:323
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: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.
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
int krk_doRecursiveModuleLoad(KrkString *name)
Load a module by a dotted name.
Definition: vm.c:1572
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
void krk_setMaximumRecursionDepth(size_t maxDepth)
Set the maximum recursion call depth.
Definition: vm.c:863
void krk_module_init_kuroko(void)
Initialize the built-in 'kuroko' module.
Definition: sys.c:227
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118