diff --git a/src/builtins.c b/src/builtins.c index 40f1e20..3376e05 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -271,6 +271,14 @@ static KrkValue _type(int argc, KrkValue argv[], int hasKw) { return OBJECT_VAL(krk_getType(argv[0])); } +KRK_FUNC(getattr,{ + FUNCTION_TAKES_AT_LEAST(2); + KrkValue object = argv[0]; + CHECK_ARG(1,str,KrkString*,property); + return krk_valueGetAttribute(object, property->chars); +}) + + #define IS_Helper(o) (krk_isInstanceOf(o, Helper)) #define AS_Helper(o) (AS_INSTANCE(o)) #define IS_LicenseReader(o) (krk_isInstanceOf(o, LicenseReader)) @@ -377,5 +385,6 @@ void _createAndBind_builtins(void) { 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."); + BUILTIN_FUNCTION("getattr", FUNC_NAME(krk,getattr), "Obtain a property of an object as if it were accessed by the dot operator."); } diff --git a/src/rline.c b/src/rline.c index df28de8..3d35bb2 100644 --- a/src/rline.c +++ b/src/rline.c @@ -555,7 +555,7 @@ char * syn_krk_types[] = { "list","dict","range", /* builtin classes */ "object","exception","isinstance","type","tuple", "print","set","any","all","bool","ord","chr","hex", - "sorted","bytes", + "sorted","bytes","getattr", NULL }; diff --git a/src/vm.c b/src/vm.c index 543ba8f..d3e2972 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1113,6 +1113,12 @@ static KrkValue krk_setclean(int argc, KrkValue argv[], int hasKw) { return NONE_VAL(); } +static KrkValue krk_import_wrapper(int argc, KrkValue argv[], int hasKw) { + if (!argc || !IS_STRING(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "expected string"); + if (!krk_doRecursiveModuleLoad(AS_STRING(argv[0]))) return NONE_VAL(); /* ImportError already raised */ + return krk_pop(); +} + void krk_initVM(int flags) { vm.globalFlags = flags & 0xFF00; @@ -1221,6 +1227,7 @@ void krk_initVM(int flags) { krk_defineNative(&vm.system->fields, "getsizeof", krk_getsize); 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_defineNative(&vm.system->fields, "importmodule", krk_import_wrapper)->doc = "Import a module by string name"; krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP)); KrkValue module_paths = krk_list_of(0,NULL,0); krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths); @@ -1719,6 +1726,17 @@ static int valueGetProperty(KrkString * name) { return 0; } +KrkValue krk_valueGetAttribute(KrkValue value, char * name) { + krk_push(OBJECT_VAL(krk_copyString(name,strlen(name)))); + krk_push(value); + if (!valueGetProperty(AS_STRING(krk_peek(1)))) { + return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name); + } + krk_swap(1); + krk_pop(); /* String */ + return krk_pop(); +} + static int valueDelProperty(KrkString * name) { if (IS_INSTANCE(krk_peek(0))) { KrkInstance* instance = AS_INSTANCE(krk_peek(0)); diff --git a/src/vm.h b/src/vm.h index 2219f07..6f65052 100644 --- a/src/vm.h +++ b/src/vm.h @@ -741,3 +741,4 @@ extern KrkValue krk_operator_lt(KrkValue,KrkValue); extern KrkValue krk_operator_gt(KrkValue,KrkValue); +extern KrkValue krk_valueGetAttribute(KrkValue value, char * name);