Eliminate builtins.krk
This commit is contained in:
parent
689cee075e
commit
90b219cdce
5
Makefile
5
Makefile
@ -64,11 +64,6 @@ modules/math.so: src/module_math.c libkuroko.so
|
||||
libkuroko.so: ${OBJS}
|
||||
${CC} ${CFLAGS} ${LDFLAGS} -shared -o $@ ${OBJS}
|
||||
|
||||
src/builtins.c: src/builtins.krk
|
||||
echo "const char krk_builtinsSrc[] = " > $@
|
||||
cat $< | sed s'/\(.*\)/\"\0\\n\"/' >> $@
|
||||
echo ";" >> $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -f ${OBJS} ${TARGET} ${MODULES} libkuroko.so src/*.o kuroko.exe
|
||||
|
@ -40,8 +40,6 @@ The interpreter binary is a thin wrapper and lives in `kuroko.c`; `rline.c` prov
|
||||
|
||||
C module sources are found in `src/` and provide optional added functionality. Each module source file corresponds to a resulting shared object of the same name that will be built to the `modules/` directory, which itself also contains modules written in Kuroko.
|
||||
|
||||
The core builtins, `builtins.krk` are embedded in `builtins.c` so they are always available to the interpreter; `builtins.c` is provided in the repository, but can be updated by the Makefile when changes to `builtins.krk` are made.
|
||||
|
||||
### Building as a Single Static Binary
|
||||
|
||||
Configuration options are available in the Makefile to build Kuroko as a static binary.
|
||||
|
@ -21,6 +21,15 @@ def interactive():
|
||||
'''Runs the detailed help tool. Currently that means just printing a longer help string.'''
|
||||
print(__introText)
|
||||
|
||||
def simple(obj):
|
||||
try:
|
||||
print(obj.__doc__)
|
||||
except:
|
||||
try:
|
||||
print(obj.__class__.__doc__)
|
||||
except:
|
||||
print('No docstring avaialble for', obj)
|
||||
|
||||
let __licenseText = '''
|
||||
Copyright (c) 2020-2021 K. Lange <klange@toaruos.org>
|
||||
|
||||
|
499
src/builtins.c
499
src/builtins.c
@ -1,49 +1,450 @@
|
||||
const char krk_builtinsSrc[] =
|
||||
"# Please avoid using double quotes or escape sequences\n"
|
||||
"# in this file to allow it to be easily converted to C.\n"
|
||||
"class Helper():\n"
|
||||
" '''You seem to already know how to use this.'''\n"
|
||||
" def __call__(self,obj=None):\n"
|
||||
" if obj is not None:\n"
|
||||
" try:\n"
|
||||
" print(obj.__doc__)\n"
|
||||
" except:\n"
|
||||
" try:\n"
|
||||
" print(obj.__class__.__doc__)\n"
|
||||
" except:\n"
|
||||
" print('No docstring avaialble for', obj)\n"
|
||||
" else:\n"
|
||||
" from help import interactive\n"
|
||||
" interactive()\n"
|
||||
" def __repr__(self):\n"
|
||||
" return 'Type help() for more help, or help(obj) to describe an object.'\n"
|
||||
"\n"
|
||||
"let help = Helper()\n"
|
||||
"\n"
|
||||
"class LicenseReader():\n"
|
||||
" def __call__(self):\n"
|
||||
" from help import __licenseText\n"
|
||||
" print(__licenseText)\n"
|
||||
" def __repr__(self):\n"
|
||||
" return 'Copyright 2020-2021 K. Lange <klange@toaruos.org>. Type `license()` for more information.'\n"
|
||||
"\n"
|
||||
"let license = LicenseReader()\n"
|
||||
"\n"
|
||||
"__builtins__.help = help\n"
|
||||
"__builtins__.license = license\n"
|
||||
"\n"
|
||||
"# this works because `kuroko` is always a built-in\n"
|
||||
"import kuroko\n"
|
||||
"kuroko.module_paths = ['./']\n"
|
||||
"if 'executable_path' in dir(kuroko):\n"
|
||||
" let pathunits = kuroko.executable_path.split(kuroko.path_sep)[:-1]\n"
|
||||
" let dirname = pathunits[-1]\n"
|
||||
" if dirname == 'bin':\n"
|
||||
" pathunits.pop(-1)\n"
|
||||
" pathunits.extend(['lib','kuroko',''])\n"
|
||||
" else:\n"
|
||||
" pathunits.extend(['modules',''])\n"
|
||||
" kuroko.module_paths.append(kuroko.path_sep.join(pathunits))\n"
|
||||
"\n"
|
||||
"return object()\n"
|
||||
;
|
||||
#include <string.h>
|
||||
#include "vm.h"
|
||||
#include "value.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
KrkClass * Helper;
|
||||
KrkClass * LicenseReader;
|
||||
|
||||
KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "wrong number of arguments or bad type, got %d\n", argc);
|
||||
|
||||
/* Create a new list instance */
|
||||
KrkValue myList = krk_list_of(0,NULL);
|
||||
krk_push(myList);
|
||||
|
||||
if (IS_INSTANCE(argv[0])) {
|
||||
/* Obtain self-reference */
|
||||
KrkInstance * self = AS_INSTANCE(argv[0]);
|
||||
|
||||
/* First add each method of the class */
|
||||
for (size_t i = 0; i < self->_class->methods.capacity; ++i) {
|
||||
if (self->_class->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
self->_class->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Then add each field of the instance */
|
||||
for (size_t i = 0; i < self->fields.capacity; ++i) {
|
||||
if (self->fields.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
self->fields.entries[i].key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IS_CLASS(argv[0])) {
|
||||
KrkClass * _class = AS_CLASS(argv[0]);
|
||||
for (size_t i = 0; i < _class->methods.capacity; ++i) {
|
||||
if (_class->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
_class->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < _class->fields.capacity; ++i) {
|
||||
if (_class->fields.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
_class->fields.entries[i].key);
|
||||
}
|
||||
}
|
||||
}
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
|
||||
for (size_t i = 0; i < type->methods.capacity; ++i) {
|
||||
if (type->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
type->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare output value */
|
||||
krk_pop();
|
||||
return myList;
|
||||
}
|
||||
|
||||
|
||||
static KrkValue _len(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "len() takes exactly one argument");
|
||||
/* Shortcuts */
|
||||
if (IS_STRING(argv[0])) return INTEGER_VAL(AS_STRING(argv[0])->codesLength);
|
||||
if (IS_TUPLE(argv[0])) return INTEGER_VAL(AS_TUPLE(argv[0])->values.count);
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (!type->_len) return krk_runtimeError(vm.exceptions.typeError, "object of type '%s' has no len()", krk_typeName(argv[0]));
|
||||
krk_push(argv[0]);
|
||||
|
||||
return krk_callSimple(OBJECT_VAL(type->_len), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _dir(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "dir() takes exactly one argument");
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (!type->_dir) {
|
||||
return krk_dirObject(argc,argv); /* Fallback */
|
||||
}
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(OBJECT_VAL(type->_dir), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _repr(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "repr() takes exactly one argument");
|
||||
|
||||
/* Everything should have a __repr__ */
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _ord(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "ord() takes exactly one argument");
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
KrkValue method;
|
||||
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_ORD], &method)) {
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(method, 1, 0);
|
||||
}
|
||||
return krk_runtimeError(vm.exceptions.argumentError, "ord() expected string of length 1, but got %s", krk_typeName(argv[0]));
|
||||
}
|
||||
|
||||
static KrkValue _chr(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "chr() takes exactly one argument");
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
KrkValue method;
|
||||
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_CHR], &method)) {
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(method, 1, 0);
|
||||
}
|
||||
return krk_runtimeError(vm.exceptions.argumentError, "chr() expected an integer, but got %s", krk_typeName(argv[0]));
|
||||
}
|
||||
|
||||
static KrkValue _hex(int argc, KrkValue argv[]) {
|
||||
if (argc != 1 || !IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions.argumentError, "hex() expects one int argument");
|
||||
char tmp[20];
|
||||
krk_integer_type x = AS_INTEGER(argv[0]);
|
||||
size_t len = sprintf(tmp, "%s0x" PRIkrk_hex, x < 0 ? "-" : "", x < 0 ? -x : x);
|
||||
return OBJECT_VAL(krk_copyString(tmp,len));
|
||||
}
|
||||
|
||||
static KrkValue _any(int argc, KrkValue argv[]) {
|
||||
#define unpackArray(counter, indexer) do { \
|
||||
for (size_t i = 0; i < counter; ++i) { \
|
||||
if (!krk_isFalsey(indexer)) return BOOLEAN_VAL(1); \
|
||||
} \
|
||||
} while (0)
|
||||
KrkValue value = argv[0];
|
||||
if (IS_TUPLE(value)) {
|
||||
unpackArray(AS_TUPLE(value)->values.count, AS_TUPLE(value)->values.values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.listClass) {
|
||||
unpackArray(AS_LIST(value)->count, AS_LIST(value)->values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.dictClass) {
|
||||
unpackArray(AS_DICT(value)->count, krk_dict_nth_key_fast(AS_DICT(value)->capacity, AS_DICT(value)->entries, i));
|
||||
} else if (IS_STRING(value)) {
|
||||
unpackArray(AS_STRING(value)->codesLength, krk_string_get(2,(KrkValue[]){value,INTEGER_VAL(i)},0));
|
||||
} else {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (type->_iter) {
|
||||
/* Create the iterator */
|
||||
size_t stackOffset = vm.stackTop - vm.stack;
|
||||
krk_push(argv[1]);
|
||||
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
|
||||
|
||||
do {
|
||||
/* Call it until it gives us itself */
|
||||
krk_push(vm.stack[stackOffset]);
|
||||
krk_push(krk_callSimple(krk_peek(0), 0, 1));
|
||||
if (krk_valuesSame(vm.stack[stackOffset], krk_peek(0))) {
|
||||
/* We're done. */
|
||||
krk_pop(); /* The result of iteration */
|
||||
krk_pop(); /* The iterator */
|
||||
break;
|
||||
}
|
||||
if (!krk_isFalsey(krk_peek(0))) {
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
krk_pop();
|
||||
} while (1);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions.typeError, "'%s' object is not iterable", krk_typeName(value));
|
||||
}
|
||||
}
|
||||
#undef unpackArray
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
|
||||
static KrkValue _all(int argc, KrkValue argv[]) {
|
||||
#define unpackArray(counter, indexer) do { \
|
||||
for (size_t i = 0; i < counter; ++i) { \
|
||||
if (krk_isFalsey(indexer)) return BOOLEAN_VAL(0); \
|
||||
} \
|
||||
} while (0)
|
||||
KrkValue value = argv[0];
|
||||
if (IS_TUPLE(value)) {
|
||||
unpackArray(AS_TUPLE(value)->values.count, AS_TUPLE(value)->values.values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.listClass) {
|
||||
unpackArray(AS_LIST(value)->count, AS_LIST(value)->values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.dictClass) {
|
||||
unpackArray(AS_DICT(value)->count, krk_dict_nth_key_fast(AS_DICT(value)->capacity, AS_DICT(value)->entries, i));
|
||||
} else if (IS_STRING(value)) {
|
||||
unpackArray(AS_STRING(value)->codesLength, krk_string_get(2,(KrkValue[]){value,INTEGER_VAL(i)},0));
|
||||
} else {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (type->_iter) {
|
||||
/* Create the iterator */
|
||||
size_t stackOffset = vm.stackTop - vm.stack;
|
||||
krk_push(argv[1]);
|
||||
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
|
||||
|
||||
do {
|
||||
/* Call it until it gives us itself */
|
||||
krk_push(vm.stack[stackOffset]);
|
||||
krk_push(krk_callSimple(krk_peek(0), 0, 1));
|
||||
if (krk_valuesSame(vm.stack[stackOffset], krk_peek(0))) {
|
||||
/* We're done. */
|
||||
krk_pop(); /* The result of iteration */
|
||||
krk_pop(); /* The iterator */
|
||||
break;
|
||||
}
|
||||
if (krk_isFalsey(krk_peek(0))) {
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
krk_pop();
|
||||
} while (1);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions.typeError, "'%s' object is not iterable", krk_typeName(value));
|
||||
}
|
||||
}
|
||||
#undef unpackArray
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
static KrkValue _print(int argc, KrkValue argv[], int hasKw) {
|
||||
KrkValue sepVal, endVal;
|
||||
char * sep = " "; size_t sepLen = 1;
|
||||
char * end = "\n"; size_t endLen = 1;
|
||||
if (hasKw) {
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("sep")), &sepVal)) {
|
||||
if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions.typeError, "'sep' should be a string, not '%s'", krk_typeName(sepVal));
|
||||
sep = AS_CSTRING(sepVal);
|
||||
sepLen = AS_STRING(sepVal)->length;
|
||||
}
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("end")), &endVal)) {
|
||||
if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions.typeError, "'end' should be a string, not '%s'", krk_typeName(endVal));
|
||||
end = AS_CSTRING(endVal);
|
||||
endLen = AS_STRING(endVal)->length;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
KrkValue printable = argv[i];
|
||||
if (IS_STRING(printable)) { /* krk_printValue runs repr */
|
||||
/* Make sure we handle nil bits correctly. */
|
||||
for (size_t j = 0; j < AS_STRING(printable)->length; ++j) {
|
||||
fputc(AS_CSTRING(printable)[j], stdout);
|
||||
}
|
||||
} else {
|
||||
krk_printValue(stdout, printable);
|
||||
}
|
||||
char * thingToPrint = (i == argc - 1) ? end : sep;
|
||||
for (size_t j = 0; j < ((i == argc - 1) ? endLen : sepLen); ++j) {
|
||||
fputc(thingToPrint[j], stdout);
|
||||
}
|
||||
}
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
/**
|
||||
* globals()
|
||||
*
|
||||
* Returns a dict of names -> values for all the globals.
|
||||
*/
|
||||
static KrkValue _globals(int argc, KrkValue argv[]) {
|
||||
/* Make a new empty dict */
|
||||
KrkValue dict = krk_dict_of(0, NULL);
|
||||
krk_push(dict);
|
||||
/* Copy the globals table into it */
|
||||
krk_tableAddAll(vm.frames[vm.frameCount-1].globals, AS_DICT(dict));
|
||||
krk_pop();
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static KrkValue _isinstance(int argc, KrkValue argv[]) {
|
||||
if (argc != 2) return krk_runtimeError(vm.exceptions.argumentError, "isinstance expects 2 arguments, got %d", argc);
|
||||
if (!IS_CLASS(argv[1])) return krk_runtimeError(vm.exceptions.typeError, "isinstance() arg 2 must be class");
|
||||
|
||||
return BOOLEAN_VAL(krk_isInstanceOf(argv[0], AS_CLASS(argv[1])));
|
||||
}
|
||||
|
||||
static KrkValue _module_repr(int argc, KrkValue argv[]) {
|
||||
KrkInstance * self = AS_INSTANCE(argv[0]);
|
||||
|
||||
KrkValue name = NONE_VAL();
|
||||
krk_tableGet(&self->fields, vm.specialMethodNames[METHOD_NAME], &name);
|
||||
|
||||
if (!IS_STRING(name)) {
|
||||
return OBJECT_VAL(S("<module>"));
|
||||
}
|
||||
|
||||
KrkValue file = NONE_VAL();
|
||||
krk_tableGet(&self->fields, vm.specialMethodNames[METHOD_FILE], &file);
|
||||
|
||||
char * tmp = malloc(50 + AS_STRING(name)->length + (IS_STRING(file) ? AS_STRING(file)->length : 20));
|
||||
if (IS_STRING(file)) {
|
||||
sprintf(tmp, "<module '%s' from '%s'>", AS_CSTRING(name), AS_CSTRING(file));
|
||||
} else {
|
||||
sprintf(tmp, "<module '%s' (built-in)>", AS_CSTRING(name));
|
||||
}
|
||||
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(tmp, strlen(tmp)));
|
||||
free(tmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* object.__str__() / object.__repr__()
|
||||
*
|
||||
* Base method for all objects to implement __str__ and __repr__.
|
||||
* Generally converts to <instance of [TYPE]> and for actual object
|
||||
* types (functions, classes, instances, strings...) also adds the pointer
|
||||
* address of the object on the heap.
|
||||
*
|
||||
* Since all types have at least a pseudo-class that should eventually
|
||||
* inheret from object() and this is object.__str__ / object.__repr__,
|
||||
* all types should have a string representation available through
|
||||
* those methods.
|
||||
*/
|
||||
static KrkValue _strBase(int argc, KrkValue argv[]) {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
size_t len = sizeof("<instance of . at 0x1234567812345678>") + type->name->length;
|
||||
char * tmp = malloc(len);
|
||||
if (IS_OBJECT(argv[0])) {
|
||||
sprintf(tmp, "<instance of %s at %p>", type->name->chars, (void*)AS_OBJECT(argv[0]));
|
||||
} else {
|
||||
sprintf(tmp, "<instance of %s>", type->name->chars);
|
||||
}
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(tmp, strlen(tmp)));
|
||||
free(tmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
static KrkValue _type(int argc, KrkValue argv[]) {
|
||||
return OBJECT_VAL(krk_getType(argv[0]));
|
||||
}
|
||||
|
||||
#define IS_Helper(o) (krk_isInstanceOf(o, Helper))
|
||||
#define AS_Helper(o) (AS_INSTANCE(o))
|
||||
#define IS_LicenseReader(o) (krk_isInstanceOf(o, LicenseReader))
|
||||
#define AS_LicenseReader(o) (AS_INSTANCE(o))
|
||||
|
||||
#define CURRENT_CTYPE KrkInstance *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
KRK_METHOD(Helper,__repr__,{
|
||||
return OBJECT_VAL(S("Type help() for more help, or help(obj) to describe an object."));
|
||||
})
|
||||
|
||||
KRK_METHOD(Helper,__call__,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (!krk_doRecursiveModuleLoad(S("help"))) return NONE_VAL();
|
||||
KrkValue helpModule;
|
||||
if (!krk_tableGet(&vm.modules, OBJECT_VAL(S("help")), &helpModule) || !IS_INSTANCE(helpModule))
|
||||
return krk_runtimeError(vm.exceptions.importError, "Could not import help module");
|
||||
|
||||
KrkValue callable = NONE_VAL();
|
||||
|
||||
if (argc == 2) {
|
||||
krk_tableGet(&AS_INSTANCE(helpModule)->fields, OBJECT_VAL(S("simple")), &callable);
|
||||
krk_push(argv[1]);
|
||||
} else {
|
||||
krk_tableGet(&AS_INSTANCE(helpModule)->fields, OBJECT_VAL(S("interactive")), &callable);
|
||||
}
|
||||
|
||||
if (!IS_NONE(callable)) {
|
||||
return krk_callSimple(callable, argc == 2, 0);
|
||||
}
|
||||
|
||||
return krk_runtimeError(vm.exceptions.typeError, "unexpected error");
|
||||
})
|
||||
|
||||
KRK_METHOD(LicenseReader,__repr__,{
|
||||
return OBJECT_VAL(S("Copyright 2020-2021 K. Lange <klange@toaruos.org>. Type `license()` for more information."));
|
||||
})
|
||||
|
||||
KRK_METHOD(LicenseReader,__call__,{
|
||||
METHOD_TAKES_NONE();
|
||||
if (!krk_doRecursiveModuleLoad(S("help"))) return NONE_VAL();
|
||||
KrkValue helpModule;
|
||||
if (!krk_tableGet(&vm.modules, OBJECT_VAL(S("help")), &helpModule) || !IS_INSTANCE(helpModule))
|
||||
return krk_runtimeError(vm.exceptions.importError, "Could not import help module");
|
||||
|
||||
KrkValue text = NONE_VAL();
|
||||
krk_tableGet(&AS_INSTANCE(helpModule)->fields, OBJECT_VAL(S("__licenseText")), &text);
|
||||
|
||||
if (IS_STRING(text)) {
|
||||
printf("%s\n", AS_CSTRING(text));
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
return krk_runtimeError(vm.exceptions.typeError, "unexpected error");
|
||||
})
|
||||
|
||||
_noexport
|
||||
void _createAndBind_builtins(void) {
|
||||
vm.objectClass = krk_newClass(S("object"), NULL);
|
||||
krk_defineNative(&vm.objectClass->methods, ":__class__", _type);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__dir__", krk_dirObject);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__str__", _strBase);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__repr__", _strBase); /* Override if necesary */
|
||||
krk_finalizeClass(vm.objectClass);
|
||||
vm.objectClass->docstring = S("Base class for all types.");
|
||||
|
||||
vm.moduleClass = krk_newClass(S("module"), vm.objectClass);
|
||||
krk_defineNative(&vm.moduleClass->methods, ".__repr__", _module_repr);
|
||||
krk_defineNative(&vm.moduleClass->methods, ".__str__", _module_repr);
|
||||
krk_finalizeClass(vm.moduleClass);
|
||||
vm.moduleClass->docstring = S("");
|
||||
|
||||
vm.builtins = krk_newInstance(vm.moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "__builtins__", (KrkObj*)vm.builtins);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "object", (KrkObj*)vm.objectClass);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "__name__", (KrkObj*)S("__builtins__"));
|
||||
krk_attachNamedValue(&vm.builtins->fields, "__file__", NONE_VAL());
|
||||
krk_attachNamedObject(&vm.builtins->fields, "__doc__",
|
||||
(KrkObj*)S("Internal module containing built-in functions and classes."));
|
||||
|
||||
krk_makeClass(vm.builtins, &Helper, "Helper", vm.objectClass);
|
||||
BIND_METHOD(Helper,__call__);
|
||||
BIND_METHOD(Helper,__repr__);
|
||||
krk_finalizeClass(Helper);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "help", (KrkObj*)krk_newInstance(Helper));
|
||||
|
||||
krk_makeClass(vm.builtins, &LicenseReader, "LicenseReader", vm.objectClass);
|
||||
BIND_METHOD(LicenseReader,__call__);
|
||||
BIND_METHOD(LicenseReader,__repr__);
|
||||
krk_finalizeClass(LicenseReader);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "license", (KrkObj*)krk_newInstance(LicenseReader));
|
||||
|
||||
BUILTIN_FUNCTION("listOf", krk_list_of, "Convert argument sequence to list object.");
|
||||
BUILTIN_FUNCTION("dictOf", krk_dict_of, "Convert argument sequence to dict object.");
|
||||
BUILTIN_FUNCTION("tupleOf",krk_tuple_of,"Convert argument sequence to tuple object.");
|
||||
|
||||
BUILTIN_FUNCTION("isinstance", _isinstance, "Determine if an object is an instance of the given class or one if its subclasses.");
|
||||
BUILTIN_FUNCTION("globals", _globals, "Return a mapping of names in the current global namespace.");
|
||||
BUILTIN_FUNCTION("dir", _dir, "Return a list of known property names for a given object.");
|
||||
BUILTIN_FUNCTION("len", _len, "Return the length of a given sequence object.");
|
||||
BUILTIN_FUNCTION("repr", _repr, "Produce a string representation of the given object.");
|
||||
BUILTIN_FUNCTION("print", _print, "Print values to the standard output descriptor.");
|
||||
BUILTIN_FUNCTION("ord", _ord, "Obtain the ordinal integer value of a codepoint or byte.");
|
||||
BUILTIN_FUNCTION("chr", _chr, "Convert an integer codepoint to its string representation.");
|
||||
BUILTIN_FUNCTION("hex", _hex, "Convert an integer value to a hexadecimal string.");
|
||||
BUILTIN_FUNCTION("any", _any, "Returns True if at least one element in the given iterable is truthy, False otherwise.");
|
||||
BUILTIN_FUNCTION("all", _all, "Returns True if every element in the given iterable is truthy, False otherwise.");
|
||||
}
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
# Please avoid using double quotes or escape sequences
|
||||
# in this file to allow it to be easily converted to C.
|
||||
class Helper():
|
||||
'''You seem to already know how to use this.'''
|
||||
def __call__(self,obj=None):
|
||||
if obj is not None:
|
||||
try:
|
||||
print(obj.__doc__)
|
||||
except:
|
||||
try:
|
||||
print(obj.__class__.__doc__)
|
||||
except:
|
||||
print('No docstring avaialble for', obj)
|
||||
else:
|
||||
from help import interactive
|
||||
interactive()
|
||||
def __repr__(self):
|
||||
return 'Type help() for more help, or help(obj) to describe an object.'
|
||||
|
||||
let help = Helper()
|
||||
|
||||
class LicenseReader():
|
||||
def __call__(self):
|
||||
from help import __licenseText
|
||||
print(__licenseText)
|
||||
def __repr__(self):
|
||||
return 'Copyright 2020-2021 K. Lange <klange@toaruos.org>. Type `license()` for more information.'
|
||||
|
||||
let license = LicenseReader()
|
||||
|
||||
__builtins__.help = help
|
||||
__builtins__.license = license
|
||||
|
||||
# this works because `kuroko` is always a built-in
|
||||
import kuroko
|
||||
kuroko.module_paths = ['./']
|
||||
if 'executable_path' in dir(kuroko):
|
||||
let pathunits = kuroko.executable_path.split(kuroko.path_sep)[:-1]
|
||||
let dirname = pathunits[-1]
|
||||
if dirname == 'bin':
|
||||
pathunits.pop(-1)
|
||||
pathunits.extend(['lib','kuroko',''])
|
||||
else:
|
||||
pathunits.extend(['modules',''])
|
||||
kuroko.module_paths.append(kuroko.path_sep.join(pathunits))
|
||||
|
||||
return object()
|
57
src/obj_base.c
Normal file
57
src/obj_base.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <string.h>
|
||||
#include "vm.h"
|
||||
#include "value.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
static KrkValue _type_init(int argc, KrkValue argv[]) {
|
||||
if (argc != 2) return krk_runtimeError(vm.exceptions.argumentError, "type() takes 1 argument");
|
||||
return OBJECT_VAL(krk_getType(argv[1]));
|
||||
}
|
||||
|
||||
/* Class.__base__ */
|
||||
static KrkValue krk_baseOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->base ? OBJECT_VAL(AS_CLASS(argv[0])->base) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__name */
|
||||
static KrkValue krk_nameOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->name ? OBJECT_VAL(AS_CLASS(argv[0])->name) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__file__ */
|
||||
static KrkValue krk_fileOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->filename ? OBJECT_VAL(AS_CLASS(argv[0])->filename) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__doc__ */
|
||||
static KrkValue krk_docOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->docstring ? OBJECT_VAL(AS_CLASS(argv[0])->docstring) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__str__() (and Class.__repr__) */
|
||||
static KrkValue _class_to_str(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
char * tmp = malloc(sizeof("<type ''>") + AS_CLASS(argv[0])->name->length);
|
||||
size_t l = sprintf(tmp, "<type '%s'>", AS_CLASS(argv[0])->name->chars);
|
||||
KrkString * out = krk_copyString(tmp,l);
|
||||
free(tmp);
|
||||
return OBJECT_VAL(out);
|
||||
}
|
||||
|
||||
void _createAndBind_type(void) {
|
||||
ADD_BASE_CLASS(vm.baseClasses.typeClass, "type", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__base__", krk_baseOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__file__", krk_fileOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__doc__", krk_docOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__name__", krk_nameOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__init__", _type_init);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__str__", _class_to_str);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__repr__", _class_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.typeClass);
|
||||
vm.baseClasses.typeClass->docstring = S("Obtain the object representation of the class of an object.");
|
||||
}
|
120
src/obj_numeric.c
Normal file
120
src/obj_numeric.c
Normal file
@ -0,0 +1,120 @@
|
||||
#include <string.h>
|
||||
#include "vm.h"
|
||||
#include "value.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
#undef IS_int
|
||||
#undef IS_bool
|
||||
#undef IS_float
|
||||
|
||||
#define IS_int(o) (IS_INTEGER(o) || krk_isInstanceOf(o,vm.baseClasses.intClass))
|
||||
#define IS_bool(o) (IS_BOOLEAN(o) || krk_isInstanceOf(o,vm.baseClasses.boolClass))
|
||||
#define IS_float(o) (IS_FLOATING(o) || krk_isInstanceOf(o,vm.baseClasses.floatClass))
|
||||
|
||||
#define IS_NoneType(o) (IS_NONE(o))
|
||||
#define AS_NoneType(o) ((char)0)
|
||||
|
||||
#define CURRENT_CTYPE krk_integer_type
|
||||
#define CURRENT_NAME self
|
||||
|
||||
KRK_METHOD(int,__init__,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (argc < 2) return INTEGER_VAL(0);
|
||||
if (IS_INTEGER(argv[1])) return argv[1];
|
||||
if (IS_STRING(argv[1])) return krk_string_int(argc-1,&argv[1],0);
|
||||
if (IS_FLOATING(argv[1])) return INTEGER_VAL(AS_FLOATING(argv[1]));
|
||||
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_BOOLEAN(argv[1]));
|
||||
return krk_runtimeError(vm.exceptions.typeError, "int() argument must be a string or a number, not '%s'", krk_typeName(argv[1]));
|
||||
})
|
||||
|
||||
KRK_METHOD(int,__str__,{
|
||||
char tmp[100];
|
||||
size_t l = sprintf(tmp, PRIkrk_int, self);
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
})
|
||||
|
||||
KRK_METHOD(int,__int__,{ return argv[0]; })
|
||||
KRK_METHOD(int,__float__,{ return FLOATING_VAL(self); })
|
||||
|
||||
KRK_METHOD(int,__chr__,{
|
||||
unsigned char bytes[5] = {0};
|
||||
size_t len = krk_codepointToBytes(self, bytes);
|
||||
return OBJECT_VAL(krk_copyString((char*)bytes, len));
|
||||
})
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE double
|
||||
|
||||
KRK_METHOD(float,__init__,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (argc < 2) return FLOATING_VAL(0.0);
|
||||
if (argc > 2) return krk_runtimeError(vm.exceptions.argumentError, "float() takes at most 1 argument");
|
||||
if (IS_STRING(argv[1])) return krk_string_float(1,&argv[1],0);
|
||||
if (IS_FLOATING(argv[1])) return argv[1];
|
||||
if (IS_INTEGER(argv[1])) return FLOATING_VAL(AS_INTEGER(argv[1]));
|
||||
if (IS_BOOLEAN(argv[1])) return FLOATING_VAL(AS_BOOLEAN(argv[1]));
|
||||
return krk_runtimeError(vm.exceptions.typeError, "float() argument must be a string or a number, not '%s'", krk_typeName(argv[1]));
|
||||
})
|
||||
|
||||
KRK_METHOD(float,__int__,{ return INTEGER_VAL(self); })
|
||||
KRK_METHOD(float,__float__,{ return argv[0]; })
|
||||
|
||||
KRK_METHOD(float,__str__,{
|
||||
char tmp[100];
|
||||
size_t l = sprintf(tmp, "%g", self);
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
})
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE char
|
||||
|
||||
KRK_METHOD(bool,__init__,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (argc < 2) return BOOLEAN_VAL(0);
|
||||
return BOOLEAN_VAL(!krk_isFalsey(argv[1]));
|
||||
})
|
||||
|
||||
KRK_METHOD(bool,__str__,{
|
||||
return OBJECT_VAL((self ? S("True") : S("False")));
|
||||
})
|
||||
|
||||
KRK_METHOD(NoneType,__str__,{
|
||||
return OBJECT_VAL(S("None"));
|
||||
})
|
||||
|
||||
#undef BIND_METHOD
|
||||
#define BIND_METHOD(klass,method) do { krk_defineNative(& _ ## klass->methods, "." #method, _ ## klass ## _ ## method); } while (0)
|
||||
_noexport
|
||||
void _createAndBind_numericClasses(void) {
|
||||
KrkClass * _int = ADD_BASE_CLASS(vm.baseClasses.intClass, "int", vm.objectClass);
|
||||
BIND_METHOD(int,__init__);
|
||||
BIND_METHOD(int,__str__);
|
||||
BIND_METHOD(int,__int__);
|
||||
BIND_METHOD(int,__chr__);
|
||||
BIND_METHOD(int,__float__);
|
||||
krk_defineNative(&_int->methods, ".__repr__", FUNC_NAME(int,__str__));
|
||||
krk_finalizeClass(_int);
|
||||
_int->docstring = S("Convert a number or string type to an integer representation.");
|
||||
|
||||
KrkClass * _float = ADD_BASE_CLASS(vm.baseClasses.floatClass, "float", vm.objectClass);
|
||||
BIND_METHOD(float,__init__);
|
||||
BIND_METHOD(float,__int__);
|
||||
BIND_METHOD(float,__float__);
|
||||
BIND_METHOD(float,__str__);
|
||||
krk_defineNative(&_float->methods, ".__repr__", FUNC_NAME(float,__str__));
|
||||
krk_finalizeClass(_float);
|
||||
_float->docstring = S("Convert a number or string type to a float representation.");
|
||||
|
||||
KrkClass * _bool = ADD_BASE_CLASS(vm.baseClasses.boolClass, "bool", vm.objectClass);
|
||||
BIND_METHOD(bool,__init__);
|
||||
BIND_METHOD(bool,__str__);
|
||||
krk_defineNative(&_bool->methods, ".__repr__", FUNC_NAME(bool,__str__));
|
||||
krk_finalizeClass(_bool);
|
||||
_bool->docstring = S("Returns False if the argument is 'falsey', otherwise True.");
|
||||
|
||||
KrkClass * _NoneType = ADD_BASE_CLASS(vm.baseClasses.noneTypeClass, "NoneType", vm.objectClass);
|
||||
BIND_METHOD(NoneType, __str__);
|
||||
krk_defineNative(&_NoneType->methods, ".__repr__", FUNC_NAME(NoneType,__str__));
|
||||
krk_finalizeClass(_NoneType);
|
||||
}
|
@ -114,6 +114,12 @@ static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
|
||||
#define IS_int(o) (IS_INTEGER(o))
|
||||
#define AS_int(o) (AS_INTEGER(o))
|
||||
|
||||
#define IS_bool(o) (IS_BOOLEAN(o))
|
||||
#define AS_bool(o) (AS_BOOLEAN(o))
|
||||
|
||||
#define IS_float(o) (IS_FLOATING(o))
|
||||
#define AS_float(o) (AS_FLOATING(o))
|
||||
|
||||
#define IS_list(o) krk_isInstanceOf(o,vm.baseClasses.listClass)
|
||||
#define AS_list(o) (KrkList*)AS_OBJECT(o)
|
||||
|
||||
|
616
src/vm.c
616
src/vm.c
@ -56,9 +56,6 @@
|
||||
/* This is macro'd to krk_vm for namespacing reasons. */
|
||||
KrkVM vm = {0};
|
||||
|
||||
/* Embedded script for extensions to builtin-ins; see builtins.c/builtins.krk */
|
||||
extern const char krk_builtinsSrc[];
|
||||
|
||||
/**
|
||||
* Reset the stack pointers, frame, upvalue list,
|
||||
* clear the exception flag and current exception;
|
||||
@ -404,66 +401,6 @@ static KrkValue krk_set_tracing(int argc, KrkValue argv[], int hasKw) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* object.__dir__()
|
||||
*/
|
||||
KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "wrong number of arguments or bad type, got %d\n", argc);
|
||||
|
||||
/* Create a new list instance */
|
||||
KrkValue myList = krk_list_of(0,NULL);
|
||||
krk_push(myList);
|
||||
|
||||
if (IS_INSTANCE(argv[0])) {
|
||||
/* Obtain self-reference */
|
||||
KrkInstance * self = AS_INSTANCE(argv[0]);
|
||||
|
||||
/* First add each method of the class */
|
||||
for (size_t i = 0; i < self->_class->methods.capacity; ++i) {
|
||||
if (self->_class->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
self->_class->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Then add each field of the instance */
|
||||
for (size_t i = 0; i < self->fields.capacity; ++i) {
|
||||
if (self->fields.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
self->fields.entries[i].key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IS_CLASS(argv[0])) {
|
||||
KrkClass * _class = AS_CLASS(argv[0]);
|
||||
for (size_t i = 0; i < _class->methods.capacity; ++i) {
|
||||
if (_class->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
_class->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < _class->fields.capacity; ++i) {
|
||||
if (_class->fields.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
_class->fields.entries[i].key);
|
||||
}
|
||||
}
|
||||
}
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
|
||||
for (size_t i = 0; i < type->methods.capacity; ++i) {
|
||||
if (type->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(myList),
|
||||
type->methods.entries[i].key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare output value */
|
||||
krk_pop();
|
||||
return myList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps values to their base classes.
|
||||
* Internal version of type().
|
||||
@ -504,52 +441,6 @@ inline KrkClass * krk_getType(KrkValue of) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* type()
|
||||
*/
|
||||
KrkValue _type(int argc, KrkValue argv[]) {
|
||||
return OBJECT_VAL(krk_getType(argv[0]));
|
||||
}
|
||||
|
||||
static KrkValue _type_init(int argc, KrkValue argv[]) {
|
||||
if (argc != 2) return krk_runtimeError(vm.exceptions.argumentError, "type() takes 1 argument");
|
||||
return OBJECT_VAL(krk_getType(argv[1]));
|
||||
}
|
||||
|
||||
/* Class.__base__ */
|
||||
static KrkValue krk_baseOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->base ? OBJECT_VAL(AS_CLASS(argv[0])->base) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__name */
|
||||
static KrkValue krk_nameOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->name ? OBJECT_VAL(AS_CLASS(argv[0])->name) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__file__ */
|
||||
static KrkValue krk_fileOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->filename ? OBJECT_VAL(AS_CLASS(argv[0])->filename) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__doc__ */
|
||||
static KrkValue krk_docOfClass(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
return AS_CLASS(argv[0])->docstring ? OBJECT_VAL(AS_CLASS(argv[0])->docstring) : NONE_VAL();
|
||||
}
|
||||
|
||||
/* Class.__str__() (and Class.__repr__) */
|
||||
static KrkValue _class_to_str(int argc, KrkValue argv[]) {
|
||||
if (!IS_CLASS(argv[0])) return krk_runtimeError(vm.exceptions.typeError, "expected class");
|
||||
char * tmp = malloc(sizeof("<type ''>") + AS_CLASS(argv[0])->name->length);
|
||||
size_t l = sprintf(tmp, "<type '%s'>", AS_CLASS(argv[0])->name->chars);
|
||||
KrkString * out = krk_copyString(tmp,l);
|
||||
free(tmp);
|
||||
return OBJECT_VAL(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* isinstance(obj,Class)
|
||||
*
|
||||
@ -566,28 +457,6 @@ int krk_isInstanceOf(KrkValue obj, KrkClass * type) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static KrkValue _isinstance(int argc, KrkValue argv[]) {
|
||||
if (argc != 2) return krk_runtimeError(vm.exceptions.argumentError, "isinstance expects 2 arguments, got %d", argc);
|
||||
if (!IS_CLASS(argv[1])) return krk_runtimeError(vm.exceptions.typeError, "isinstance() arg 2 must be class");
|
||||
|
||||
return BOOLEAN_VAL(krk_isInstanceOf(argv[0], AS_CLASS(argv[1])));
|
||||
}
|
||||
|
||||
/**
|
||||
* globals()
|
||||
*
|
||||
* Returns a dict of names -> values for all the globals.
|
||||
*/
|
||||
static KrkValue krk_globals(int argc, KrkValue argv[]) {
|
||||
/* Make a new empty dict */
|
||||
KrkValue dict = krk_dict_of(0, NULL);
|
||||
krk_push(dict);
|
||||
/* Copy the globals table into it */
|
||||
krk_tableAddAll(vm.frames[vm.frameCount-1].globals, AS_DICT(dict));
|
||||
krk_pop();
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static int checkArgumentCount(KrkClosure * closure, int argCount) {
|
||||
int minArgs = closure->function->requiredArgs;
|
||||
@ -1147,165 +1016,6 @@ _badSyntaxError:
|
||||
krk_finalizeClass(obj); \
|
||||
} while (0)
|
||||
|
||||
/** native method that returns its first arg; useful for int(INT), etc. */
|
||||
KrkValue _noop(int argc, KrkValue argv[]) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
/* float.__int__() */
|
||||
static KrkValue _floating_to_int(int argc, KrkValue argv[]) {
|
||||
return INTEGER_VAL((long)AS_FLOATING(argv[0]));
|
||||
}
|
||||
|
||||
/* int.__float__() */
|
||||
static KrkValue _int_to_floating(int argc, KrkValue argv[]) {
|
||||
return FLOATING_VAL((double)AS_INTEGER(argv[0]));
|
||||
}
|
||||
|
||||
/* int.__chr__() */
|
||||
static KrkValue _int_to_char(int argc, KrkValue argv[]) {
|
||||
krk_integer_type value = AS_INTEGER(argv[0]);
|
||||
unsigned char bytes[5] = {0};
|
||||
size_t len = krk_codepointToBytes(value, bytes);
|
||||
return OBJECT_VAL(krk_copyString((char*)bytes,len));
|
||||
}
|
||||
|
||||
static KrkValue _print(int argc, KrkValue argv[], int hasKw) {
|
||||
KrkValue sepVal, endVal;
|
||||
char * sep = " "; size_t sepLen = 1;
|
||||
char * end = "\n"; size_t endLen = 1;
|
||||
if (hasKw) {
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("sep")), &sepVal)) {
|
||||
if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions.typeError, "'sep' should be a string, not '%s'", krk_typeName(sepVal));
|
||||
sep = AS_CSTRING(sepVal);
|
||||
sepLen = AS_STRING(sepVal)->length;
|
||||
}
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("end")), &endVal)) {
|
||||
if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions.typeError, "'end' should be a string, not '%s'", krk_typeName(endVal));
|
||||
end = AS_CSTRING(endVal);
|
||||
endLen = AS_STRING(endVal)->length;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
KrkValue printable = argv[i];
|
||||
if (IS_STRING(printable)) { /* krk_printValue runs repr */
|
||||
/* Make sure we handle nil bits correctly. */
|
||||
for (size_t j = 0; j < AS_STRING(printable)->length; ++j) {
|
||||
fputc(AS_CSTRING(printable)[j], stdout);
|
||||
}
|
||||
} else {
|
||||
krk_printValue(stdout, printable);
|
||||
}
|
||||
char * thingToPrint = (i == argc - 1) ? end : sep;
|
||||
for (size_t j = 0; j < ((i == argc - 1) ? endLen : sepLen); ++j) {
|
||||
fputc(thingToPrint[j], stdout);
|
||||
}
|
||||
}
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static KrkValue _int_init(int argc, KrkValue argv[]) {
|
||||
if (argc < 2) return INTEGER_VAL(0);
|
||||
if (IS_INTEGER(argv[1])) return argv[1];
|
||||
if (IS_STRING(argv[1])) return krk_string_int(argc-1,&argv[1],0);
|
||||
if (IS_FLOATING(argv[1])) return INTEGER_VAL(AS_FLOATING(argv[1]));
|
||||
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_BOOLEAN(argv[1]));
|
||||
return krk_runtimeError(vm.exceptions.typeError, "int() argument must be a string or a number, not '%s'", krk_typeName(argv[1]));
|
||||
}
|
||||
|
||||
static KrkValue _float_init(int argc, KrkValue argv[]) {
|
||||
if (argc < 1) return FLOATING_VAL(0.0);
|
||||
if (argc > 2) return krk_runtimeError(vm.exceptions.argumentError, "float() takes at most 1 argument");
|
||||
if (IS_STRING(argv[1])) return krk_string_float(1,&argv[1],0);
|
||||
if (IS_FLOATING(argv[1])) return argv[1];
|
||||
if (IS_INTEGER(argv[1])) return FLOATING_VAL(AS_INTEGER(argv[1]));
|
||||
if (IS_BOOLEAN(argv[1])) return FLOATING_VAL(AS_BOOLEAN(argv[1]));
|
||||
return krk_runtimeError(vm.exceptions.typeError, "float() argument must be a string or a number, not '%s'", krk_typeName(argv[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* object.__str__() / object.__repr__()
|
||||
*
|
||||
* Base method for all objects to implement __str__ and __repr__.
|
||||
* Generally converts to <instance of [TYPE]> and for actual object
|
||||
* types (functions, classes, instances, strings...) also adds the pointer
|
||||
* address of the object on the heap.
|
||||
*
|
||||
* Since all types have at least a pseudo-class that should eventually
|
||||
* inheret from object() and this is object.__str__ / object.__repr__,
|
||||
* all types should have a string representation available through
|
||||
* those methods.
|
||||
*/
|
||||
static KrkValue _strBase(int argc, KrkValue argv[]) {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
size_t len = sizeof("<instance of . at 0x1234567812345678>") + type->name->length;
|
||||
char * tmp = malloc(len);
|
||||
if (IS_OBJECT(argv[0])) {
|
||||
sprintf(tmp, "<instance of %s at %p>", type->name->chars, (void*)AS_OBJECT(argv[0]));
|
||||
} else {
|
||||
sprintf(tmp, "<instance of %s>", type->name->chars);
|
||||
}
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(tmp, strlen(tmp)));
|
||||
free(tmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
static KrkValue _module_repr(int argc, KrkValue argv[]) {
|
||||
KrkInstance * self = AS_INSTANCE(argv[0]);
|
||||
|
||||
KrkValue name = NONE_VAL();
|
||||
krk_tableGet(&self->fields, vm.specialMethodNames[METHOD_NAME], &name);
|
||||
|
||||
if (!IS_STRING(name)) {
|
||||
return OBJECT_VAL(S("<module>"));
|
||||
}
|
||||
|
||||
KrkValue file = NONE_VAL();
|
||||
krk_tableGet(&self->fields, vm.specialMethodNames[METHOD_FILE], &file);
|
||||
|
||||
char * tmp = malloc(50 + AS_STRING(name)->length + (IS_STRING(file) ? AS_STRING(file)->length : 20));
|
||||
if (IS_STRING(file)) {
|
||||
sprintf(tmp, "<module '%s' from '%s'>", AS_CSTRING(name), AS_CSTRING(file));
|
||||
} else {
|
||||
sprintf(tmp, "<module '%s' (built-in)>", AS_CSTRING(name));
|
||||
}
|
||||
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(tmp, strlen(tmp)));
|
||||
free(tmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* int.__str__()
|
||||
*
|
||||
* Unlike Python, dot accessors are perfectly valid and work as you'd expect
|
||||
* them to in Kuroko, so we can do 123.__str__() and get the string "123".
|
||||
*
|
||||
* TODO: Implement format options here so we can get different widths,
|
||||
* hex/octal/binary representations, etc.
|
||||
*/
|
||||
static KrkValue _int_to_str(int argc, KrkValue argv[]) {
|
||||
char tmp[100];
|
||||
size_t l = sprintf(tmp, PRIkrk_int, (krk_integer_type)AS_INTEGER(argv[0]));
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
}
|
||||
|
||||
/**
|
||||
* float.__str__()
|
||||
*/
|
||||
static KrkValue _float_to_str(int argc, KrkValue argv[]) {
|
||||
char tmp[100];
|
||||
size_t l = sprintf(tmp, "%g", AS_FLOATING(argv[0]));
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
}
|
||||
|
||||
/**
|
||||
* bool.__str__() -> "True" or "False"
|
||||
*/
|
||||
static KrkValue _bool_to_str(int argc, KrkValue argv[]) {
|
||||
return OBJECT_VAL((AS_BOOLEAN(argv[0]) ? S("True") : S("False")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of truthiness.
|
||||
*
|
||||
@ -1315,7 +1025,7 @@ static KrkValue _bool_to_str(int argc, KrkValue argv[]) {
|
||||
* Or in more managed code terms, `if None`, `if False`, and `if 0` are all
|
||||
* going to take the else branch.
|
||||
*/
|
||||
static int isFalsey(KrkValue value) {
|
||||
int krk_isFalsey(KrkValue value) {
|
||||
switch (value.type) {
|
||||
case VAL_NONE: return 1;
|
||||
case VAL_BOOLEAN: return !AS_BOOLEAN(value);
|
||||
@ -1340,179 +1050,6 @@ static int isFalsey(KrkValue value) {
|
||||
return 0; /* Assume anything else is truthy */
|
||||
}
|
||||
|
||||
static KrkValue _bool_init(int argc, KrkValue argv[]) {
|
||||
if (argc < 2) return BOOLEAN_VAL(0);
|
||||
if (argc > 2) return krk_runtimeError(vm.exceptions.argumentError, "bool() takes at most 1 argument");
|
||||
return BOOLEAN_VAL(!isFalsey(argv[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* None.__str__() -> "None"
|
||||
*/
|
||||
static KrkValue _none_to_str(int argc, KrkValue argv[]) {
|
||||
return OBJECT_VAL(S("None"));
|
||||
}
|
||||
|
||||
static KrkValue _len(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "len() takes exactly one argument");
|
||||
/* Shortcuts */
|
||||
if (IS_STRING(argv[0])) return INTEGER_VAL(AS_STRING(argv[0])->codesLength);
|
||||
if (IS_TUPLE(argv[0])) return INTEGER_VAL(AS_TUPLE(argv[0])->values.count);
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (!type->_len) return krk_runtimeError(vm.exceptions.typeError, "object of type '%s' has no len()", krk_typeName(argv[0]));
|
||||
krk_push(argv[0]);
|
||||
|
||||
return krk_callSimple(OBJECT_VAL(type->_len), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _dir(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "dir() takes exactly one argument");
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (!type->_dir) {
|
||||
return krk_dirObject(argc,argv); /* Fallback */
|
||||
}
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(OBJECT_VAL(type->_dir), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _repr(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "repr() takes exactly one argument");
|
||||
|
||||
/* Everything should have a __repr__ */
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
|
||||
}
|
||||
|
||||
static KrkValue _ord(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "ord() takes exactly one argument");
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
KrkValue method;
|
||||
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_ORD], &method)) {
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(method, 1, 0);
|
||||
}
|
||||
return krk_runtimeError(vm.exceptions.argumentError, "ord() expected string of length 1, but got %s", krk_typeName(argv[0]));
|
||||
}
|
||||
|
||||
static KrkValue _chr(int argc, KrkValue argv[]) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError, "chr() takes exactly one argument");
|
||||
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
KrkValue method;
|
||||
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_CHR], &method)) {
|
||||
krk_push(argv[0]);
|
||||
return krk_callSimple(method, 1, 0);
|
||||
}
|
||||
return krk_runtimeError(vm.exceptions.argumentError, "chr() expected an integer, but got %s", krk_typeName(argv[0]));
|
||||
}
|
||||
|
||||
static KrkValue _hex(int argc, KrkValue argv[]) {
|
||||
if (argc != 1 || !IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions.argumentError, "hex() expects one int argument");
|
||||
char tmp[20];
|
||||
krk_integer_type x = AS_INTEGER(argv[0]);
|
||||
size_t len = sprintf(tmp, "%s0x" PRIkrk_hex, x < 0 ? "-" : "", x < 0 ? -x : x);
|
||||
return OBJECT_VAL(krk_copyString(tmp,len));
|
||||
}
|
||||
|
||||
static KrkValue _any(int argc, KrkValue argv[]) {
|
||||
#define unpackArray(counter, indexer) do { \
|
||||
for (size_t i = 0; i < counter; ++i) { \
|
||||
if (!isFalsey(indexer)) return BOOLEAN_VAL(1); \
|
||||
} \
|
||||
} while (0)
|
||||
KrkValue value = argv[0];
|
||||
if (IS_TUPLE(value)) {
|
||||
unpackArray(AS_TUPLE(value)->values.count, AS_TUPLE(value)->values.values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.listClass) {
|
||||
unpackArray(AS_LIST(value)->count, AS_LIST(value)->values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.dictClass) {
|
||||
unpackArray(AS_DICT(value)->count, krk_dict_nth_key_fast(AS_DICT(value)->capacity, AS_DICT(value)->entries, i));
|
||||
} else if (IS_STRING(value)) {
|
||||
unpackArray(AS_STRING(value)->codesLength, krk_string_get(2,(KrkValue[]){value,INTEGER_VAL(i)},0));
|
||||
} else {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (type->_iter) {
|
||||
/* Create the iterator */
|
||||
size_t stackOffset = vm.stackTop - vm.stack;
|
||||
krk_push(argv[1]);
|
||||
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
|
||||
|
||||
do {
|
||||
/* Call it until it gives us itself */
|
||||
krk_push(vm.stack[stackOffset]);
|
||||
krk_push(krk_callSimple(krk_peek(0), 0, 1));
|
||||
if (krk_valuesSame(vm.stack[stackOffset], krk_peek(0))) {
|
||||
/* We're done. */
|
||||
krk_pop(); /* The result of iteration */
|
||||
krk_pop(); /* The iterator */
|
||||
break;
|
||||
}
|
||||
if (!isFalsey(krk_peek(0))) {
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
krk_pop();
|
||||
} while (1);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions.typeError, "'%s' object is not iterable", krk_typeName(value));
|
||||
}
|
||||
}
|
||||
#undef unpackArray
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
|
||||
static KrkValue _all(int argc, KrkValue argv[]) {
|
||||
#define unpackArray(counter, indexer) do { \
|
||||
for (size_t i = 0; i < counter; ++i) { \
|
||||
if (isFalsey(indexer)) return BOOLEAN_VAL(0); \
|
||||
} \
|
||||
} while (0)
|
||||
KrkValue value = argv[0];
|
||||
if (IS_TUPLE(value)) {
|
||||
unpackArray(AS_TUPLE(value)->values.count, AS_TUPLE(value)->values.values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.listClass) {
|
||||
unpackArray(AS_LIST(value)->count, AS_LIST(value)->values[i]);
|
||||
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.dictClass) {
|
||||
unpackArray(AS_DICT(value)->count, krk_dict_nth_key_fast(AS_DICT(value)->capacity, AS_DICT(value)->entries, i));
|
||||
} else if (IS_STRING(value)) {
|
||||
unpackArray(AS_STRING(value)->codesLength, krk_string_get(2,(KrkValue[]){value,INTEGER_VAL(i)},0));
|
||||
} else {
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
if (type->_iter) {
|
||||
/* Create the iterator */
|
||||
size_t stackOffset = vm.stackTop - vm.stack;
|
||||
krk_push(argv[1]);
|
||||
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
|
||||
|
||||
do {
|
||||
/* Call it until it gives us itself */
|
||||
krk_push(vm.stack[stackOffset]);
|
||||
krk_push(krk_callSimple(krk_peek(0), 0, 1));
|
||||
if (krk_valuesSame(vm.stack[stackOffset], krk_peek(0))) {
|
||||
/* We're done. */
|
||||
krk_pop(); /* The result of iteration */
|
||||
krk_pop(); /* The iterator */
|
||||
break;
|
||||
}
|
||||
if (isFalsey(krk_peek(0))) {
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
krk_pop();
|
||||
} while (1);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions.typeError, "'%s' object is not iterable", krk_typeName(value));
|
||||
}
|
||||
}
|
||||
#undef unpackArray
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
static KrkValue krk_collectGarbage_wrapper(int argc, KrkValue argv[]) {
|
||||
return INTEGER_VAL(krk_collectGarbage());
|
||||
}
|
||||
@ -1636,49 +1173,18 @@ void krk_initVM(int flags) {
|
||||
vm.specialMethodNames[i] = OBJECT_VAL(krk_copyString(_methods[i].s, _methods[i].len));
|
||||
}
|
||||
|
||||
/**
|
||||
* class object()
|
||||
*
|
||||
* The base class for all types.
|
||||
* Defines the last-resort implementation of __str__, __repr__, and __dir__.
|
||||
*/
|
||||
vm.objectClass = krk_newClass(S("object"), NULL);
|
||||
|
||||
krk_defineNative(&vm.objectClass->methods, ":__class__", _type);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__dir__", krk_dirObject);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__str__", _strBase);
|
||||
krk_defineNative(&vm.objectClass->methods, ".__repr__", _strBase); /* Override if necesary */
|
||||
krk_finalizeClass(vm.objectClass);
|
||||
vm.objectClass->docstring = S("Base class for all types.");
|
||||
|
||||
/**
|
||||
* class module(object)
|
||||
*
|
||||
* When files are imported as modules, their global namespace is the fields
|
||||
* table of an instance of this class. All modules also end up with their
|
||||
* names and file paths as __name__ and __file__.
|
||||
*/
|
||||
vm.moduleClass = krk_newClass(S("module"), vm.objectClass);
|
||||
krk_defineNative(&vm.moduleClass->methods, ".__repr__", _module_repr);
|
||||
krk_defineNative(&vm.moduleClass->methods, ".__str__", _module_repr);
|
||||
krk_finalizeClass(vm.moduleClass);
|
||||
vm.moduleClass->docstring = S("");
|
||||
|
||||
/**
|
||||
* __builtins__ = module()
|
||||
*
|
||||
* The builtins namespace is always available underneath the current
|
||||
* globals namespace, and is also added to all modules as __builtins__
|
||||
* for direct references (eg., in case one of the names is shadowed
|
||||
* by a global).
|
||||
*/
|
||||
vm.builtins = krk_newInstance(vm.moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "__builtins__", (KrkObj*)vm.builtins);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "object", (KrkObj*)vm.objectClass);
|
||||
krk_attachNamedObject(&vm.builtins->fields, "__name__", (KrkObj*)S("__builtins__"));
|
||||
krk_attachNamedValue(&vm.builtins->fields, "__file__", NONE_VAL());
|
||||
krk_attachNamedObject(&vm.builtins->fields, "__doc__",
|
||||
(KrkObj*)S("Internal module containing built-in functions and classes."));
|
||||
/* Build classes for basic types */
|
||||
_createAndBind_builtins();
|
||||
_createAndBind_type();
|
||||
_createAndBind_numericClasses();
|
||||
_createAndBind_strClass();
|
||||
_createAndBind_listClass();
|
||||
_createAndBind_tupleClass();
|
||||
_createAndBind_bytesClass();
|
||||
_createAndBind_dictClass();
|
||||
_createAndBind_functionClass();
|
||||
_createAndBind_rangeClass();
|
||||
_createAndBind_setClass();
|
||||
|
||||
/**
|
||||
* kuroko = module()
|
||||
@ -1699,10 +1205,29 @@ void krk_initVM(int flags) {
|
||||
krk_defineNative(&vm.system->fields, "set_clean_output", krk_setclean);
|
||||
krk_defineNative(&vm.system->fields, "set_tracing", krk_set_tracing)->doc = "Toggle debugging modes.";
|
||||
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
|
||||
KrkValue module_paths = krk_list_of(0,NULL);
|
||||
krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths);
|
||||
krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(S("./")));
|
||||
if (vm.binpath) {
|
||||
krk_attachNamedObject(&vm.system->fields, "executable_path", (KrkObj*)krk_takeString(vm.binpath, strlen(vm.binpath)));
|
||||
char * dir = strdup(vm.binpath);
|
||||
char * slash = strrchr(dir,'/');
|
||||
if (slash) *slash = '\0';
|
||||
if (strstr(dir,"/bin") == (dir + strlen(dir) - 4)) {
|
||||
slash = strrchr(dir,'/');
|
||||
if (slash) *slash = '\0';
|
||||
char * out = malloc(sizeof("/lib/kuroko/") + strlen(dir));
|
||||
size_t len = sprintf(out,"%s/lib/kuroko/", dir);
|
||||
krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(krk_takeString(out, len)));
|
||||
} else {
|
||||
char * out = malloc(sizeof("/modules/") + strlen(dir));
|
||||
size_t len = sprintf(out,"%s/modules/", dir);
|
||||
krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(krk_takeString(out, len)));
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gc = module()
|
||||
*
|
||||
@ -1738,77 +1263,6 @@ void krk_initVM(int flags) {
|
||||
krk_defineNative(&vm.exceptions.syntaxError->methods, ".__repr__", _syntaxerror_repr);
|
||||
krk_finalizeClass(vm.exceptions.syntaxError);
|
||||
|
||||
/* Build classes for basic types */
|
||||
ADD_BASE_CLASS(vm.baseClasses.typeClass, "type", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__base__", krk_baseOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__file__", krk_fileOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__doc__", krk_docOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ":__name__", krk_nameOfClass);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__init__", _type_init);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__str__", _class_to_str);
|
||||
krk_defineNative(&vm.baseClasses.typeClass->methods, ".__repr__", _class_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.typeClass);
|
||||
vm.baseClasses.typeClass->docstring = S("Obtain the object representation of the class of an object.");
|
||||
ADD_BASE_CLASS(vm.baseClasses.intClass, "int", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__init__", _int_init);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__int__", _noop);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__float__", _int_to_floating);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__chr__", _int_to_char);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__str__", _int_to_str);
|
||||
krk_defineNative(&vm.baseClasses.intClass->methods, ".__repr__", _int_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.intClass);
|
||||
vm.baseClasses.intClass->docstring = S("Convert a number or string type to an integer representation.");
|
||||
ADD_BASE_CLASS(vm.baseClasses.floatClass, "float", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, ".__init__", _float_init);
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, ".__int__", _floating_to_int);
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, ".__float__", _noop);
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, ".__str__", _float_to_str);
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, ".__repr__", _float_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.floatClass);
|
||||
vm.baseClasses.floatClass->docstring = S("Convert a number or string type to a float representation.");
|
||||
ADD_BASE_CLASS(vm.baseClasses.boolClass, "bool", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.boolClass->methods, ".__init__", _bool_init);
|
||||
krk_defineNative(&vm.baseClasses.boolClass->methods, ".__str__", _bool_to_str);
|
||||
krk_defineNative(&vm.baseClasses.boolClass->methods, ".__repr__", _bool_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.boolClass);
|
||||
vm.baseClasses.floatClass->docstring = S("Returns False if the argument is 'falsey', otherwise True.");
|
||||
/* TODO: Don't attach */
|
||||
ADD_BASE_CLASS(vm.baseClasses.noneTypeClass, "NoneType", vm.objectClass);
|
||||
krk_defineNative(&vm.baseClasses.noneTypeClass->methods, ".__str__", _none_to_str);
|
||||
krk_defineNative(&vm.baseClasses.noneTypeClass->methods, ".__repr__", _none_to_str);
|
||||
krk_finalizeClass(vm.baseClasses.noneTypeClass);
|
||||
_createAndBind_strClass();
|
||||
_createAndBind_listClass();
|
||||
_createAndBind_tupleClass();
|
||||
_createAndBind_bytesClass();
|
||||
_createAndBind_dictClass();
|
||||
_createAndBind_functionClass();
|
||||
_createAndBind_rangeClass();
|
||||
_createAndBind_setClass();
|
||||
|
||||
/* Build global builtin functions. */
|
||||
BUILTIN_FUNCTION("listOf", krk_list_of, "Convert argument sequence to list object.");
|
||||
BUILTIN_FUNCTION("dictOf", krk_dict_of, "Convert argument sequence to dict object.");
|
||||
BUILTIN_FUNCTION("tupleOf",krk_tuple_of,"Convert argument sequence to tuple object.");
|
||||
BUILTIN_FUNCTION("isinstance", _isinstance, "Determine if an object is an instance of the given class or one if its subclasses.");
|
||||
BUILTIN_FUNCTION("globals", krk_globals, "Return a mapping of names in the current global namespace.");
|
||||
BUILTIN_FUNCTION("dir", _dir, "Return a list of known property names for a given object.");
|
||||
BUILTIN_FUNCTION("len", _len, "Return the length of a given sequence object.");
|
||||
BUILTIN_FUNCTION("repr", _repr, "Produce a string representation of the given object.");
|
||||
BUILTIN_FUNCTION("print", _print, "Print values to the standard output descriptor.");
|
||||
BUILTIN_FUNCTION("ord", _ord, "Obtain the ordinal integer value of a codepoint or byte.");
|
||||
BUILTIN_FUNCTION("chr", _chr, "Convert an integer codepoint to its string representation.");
|
||||
BUILTIN_FUNCTION("hex", _hex, "Convert an integer value to a hexadecimal string.");
|
||||
BUILTIN_FUNCTION("any", _any, "Returns True if at least one element in the given iterable is truthy, False otherwise.");
|
||||
BUILTIN_FUNCTION("all", _all, "Returns True if every element in the given iterable is truthy, False otherwise.");
|
||||
|
||||
/* This module is slowly being deprecated. */
|
||||
KrkValue builtinsModule = krk_interpret(krk_builtinsSrc,1,"__builtins__","__builtins__");
|
||||
if (!IS_OBJECT(builtinsModule)) {
|
||||
/* ... hence, this is a warning and not a complete failure. */
|
||||
fprintf(stderr, "VM startup failure: Failed to load __builtins__ module.\n");
|
||||
}
|
||||
|
||||
/* The VM is now ready to start executing code. */
|
||||
krk_resetStack();
|
||||
KRK_RESUME_GC();
|
||||
@ -2453,7 +1907,7 @@ static KrkValue run() {
|
||||
case OP_NONE: krk_push(NONE_VAL()); break;
|
||||
case OP_TRUE: krk_push(BOOLEAN_VAL(1)); break;
|
||||
case OP_FALSE: krk_push(BOOLEAN_VAL(0)); break;
|
||||
case OP_NOT: krk_push(BOOLEAN_VAL(isFalsey(krk_pop()))); break;
|
||||
case OP_NOT: krk_push(BOOLEAN_VAL(krk_isFalsey(krk_pop()))); break;
|
||||
case OP_POP: krk_pop(); break;
|
||||
case OP_DEFINE_GLOBAL_LONG:
|
||||
case OP_DEFINE_GLOBAL: {
|
||||
@ -2516,12 +1970,12 @@ static KrkValue run() {
|
||||
}
|
||||
case OP_JUMP_IF_FALSE: {
|
||||
uint16_t offset = readBytes(frame, 2);
|
||||
if (isFalsey(krk_peek(0))) frame->ip += offset;
|
||||
if (krk_isFalsey(krk_peek(0))) frame->ip += offset;
|
||||
break;
|
||||
}
|
||||
case OP_JUMP_IF_TRUE: {
|
||||
uint16_t offset = readBytes(frame, 2);
|
||||
if (!isFalsey(krk_peek(0))) frame->ip += offset;
|
||||
if (!krk_isFalsey(krk_peek(0))) frame->ip += offset;
|
||||
break;
|
||||
}
|
||||
case OP_JUMP: {
|
||||
|
7
src/vm.h
7
src/vm.h
@ -181,8 +181,9 @@ extern KrkValue krk_dict_nth_key_fast(size_t capacity, KrkTableEntry * entries,
|
||||
|
||||
extern KrkValue krk_tuple_of(int argc, KrkValue argv[]);
|
||||
|
||||
extern KrkValue _noop(int argc, KrkValue argv[]);
|
||||
extern int krk_isFalsey(KrkValue value);
|
||||
|
||||
extern void _createAndBind_numericClasses(void);
|
||||
extern void _createAndBind_strClass(void);
|
||||
extern void _createAndBind_listClass(void);
|
||||
extern void _createAndBind_tupleClass(void);
|
||||
@ -191,3 +192,7 @@ extern void _createAndBind_dictClass(void);
|
||||
extern void _createAndBind_functionClass(void);
|
||||
extern void _createAndBind_rangeClass(void);
|
||||
extern void _createAndBind_setClass(void);
|
||||
extern void _createAndBind_builtins(void);
|
||||
extern void _createAndBind_type(void);
|
||||
|
||||
extern int krk_doRecursiveModuleLoad(KrkString * name);
|
||||
|
Loading…
Reference in New Issue
Block a user