diff --git a/scripts/generate_native.py b/scripts/generate_native.py index 54f79fc..35d3b76 100644 --- a/scripts/generate_native.py +++ b/scripts/generate_native.py @@ -23,6 +23,7 @@ PK_API = "pk_api" PK_API_TYPE = "PkNativeApi" PK_API_INIT = 'pkInitApi' PK_EXPORT_MODULE = 'pkExportModule' +PK_CLEANUP_MODULE = 'pkCleanupModule' API_DEF = f'''\ static {PK_API_TYPE} {PK_API}; @@ -147,6 +148,7 @@ def generate(): fp.write(f'#define PK_API_INIT_FN_NAME "{PK_API_INIT}" \n') fp.write(f'#define PK_EXPORT_FN_NAME "{PK_EXPORT_MODULE}" \n\n') + fp.write(f'#define PK_CLEANUP_FN_NAME "{PK_CLEANUP_MODULE}" \n\n') fp.write(f'typedef void (*{PK_API_INIT}Fn)({PK_API_TYPE}*);\n') fp.write(f'typedef PkHandle* (*{PK_EXPORT_MODULE}Fn)(PKVM*);\n') fp.write(f'\n') diff --git a/src/core/compiler.c b/src/core/compiler.c index af0c21d..0aa0c09 100644 --- a/src/core/compiler.c +++ b/src/core/compiler.c @@ -2038,6 +2038,7 @@ static void exprName(Compiler* compiler) { void exprOr(Compiler* compiler) { emitOpcode(compiler, OP_OR); int orpatch = emitShort(compiler, 0xffff); //< Will be patched. + skipNewLines(compiler); parsePrecedence(compiler, PREC_LOGICAL_OR); patchJump(compiler, orpatch); } @@ -2045,6 +2046,7 @@ void exprOr(Compiler* compiler) { void exprAnd(Compiler* compiler) { emitOpcode(compiler, OP_AND); int andpatch = emitShort(compiler, 0xffff); //< Will be patched. + skipNewLines(compiler); parsePrecedence(compiler, PREC_LOGICAL_AND); patchJump(compiler, andpatch); } diff --git a/src/core/public.c b/src/core/public.c index 11c1b7a..2f67661 100644 --- a/src/core/public.c +++ b/src/core/public.c @@ -826,6 +826,14 @@ void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle) { SET_SLOT(index, handle->value); } +uint32_t pkGetSlotHash(PKVM* vm, int index) { + CHECK_FIBER_EXISTS(vm); + VALIDATE_SLOT_INDEX(index); + Var value = SLOT(index); + ASSERT(!IS_OBJ(value) || isObjectHashable(AS_OBJ(value)->type), OOPS); + return varHashValue(value); +} + bool pkSetAttribute(PKVM* vm, int instance, const char* name, int value) { CHECK_FIBER_EXISTS(vm); CHECK_ARG_NULL(name); diff --git a/src/core/value.h b/src/core/value.h index c43b6b2..b0098db 100644 --- a/src/core/value.h +++ b/src/core/value.h @@ -801,7 +801,7 @@ String* toString(PKVM* vm, const Var value); // Returns the representation version of the [value], similar to python's // __repr__() method. -String * toRepr(PKVM * vm, const Var value); +String* toRepr(PKVM * vm, const Var value); // Returns the truthy value of the var. bool toBool(Var v); diff --git a/src/include/pocketlang.h b/src/include/pocketlang.h index f5bd0ed..11e5258 100644 --- a/src/include/pocketlang.h +++ b/src/include/pocketlang.h @@ -426,6 +426,10 @@ PK_PUBLIC void pkSetSlotStringFmt(PKVM* vm, int index, const char* fmt, ...); // it's released by yourself. PK_PUBLIC void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle); +// Returns the hash of the [index] slot value. The value at the [index] must be +// hashable. +PK_PUBLIC uint32_t pkGetSlotHash(PKVM* vm, int index); + /*****************************************************************************/ /* POCKET FFI */ /*****************************************************************************/ diff --git a/src/libs/gen/nativeapi.h b/src/libs/gen/nativeapi.h index b7cb54e..865cfdb 100644 --- a/src/libs/gen/nativeapi.h +++ b/src/libs/gen/nativeapi.h @@ -54,6 +54,7 @@ typedef void (*pkSetSlotNumber_t)(PKVM*, int, double); typedef void (*pkSetSlotString_t)(PKVM*, int, const char*); typedef void (*pkSetSlotStringLength_t)(PKVM*, int, const char*, uint32_t); typedef void (*pkSetSlotHandle_t)(PKVM*, int, PkHandle*); +typedef uint32_t (*pkGetSlotHash_t)(PKVM*, int); typedef void (*pkPlaceSelf_t)(PKVM*, int); typedef void (*pkGetClass_t)(PKVM*, int, int); typedef bool (*pkNewInstance_t)(PKVM*, int, int, int, int); @@ -113,6 +114,7 @@ typedef struct { pkSetSlotString_t pkSetSlotString_ptr; pkSetSlotStringLength_t pkSetSlotStringLength_ptr; pkSetSlotHandle_t pkSetSlotHandle_ptr; + pkGetSlotHash_t pkGetSlotHash_ptr; pkPlaceSelf_t pkPlaceSelf_ptr; pkGetClass_t pkGetClass_ptr; pkNewInstance_t pkNewInstance_ptr; @@ -129,8 +131,9 @@ typedef struct { pkImportModule_t pkImportModule_ptr; } PkNativeApi; -#define PK_API_INIT_FN_NAME "pkInitApi" -#define PK_EXPORT_FN_NAME "pkExportModule" +#define PK_API_INIT_FN_NAME "pkInitApi" +#define PK_EXPORT_FN_NAME "pkExportModule" +#define PK_CLEANUP_FN_NAME "pkCleanupModule" typedef void (*pkInitApiFn)(PkNativeApi*); typedef PkHandle* (*pkExportModuleFn)(PKVM*); @@ -184,6 +187,7 @@ PkNativeApi pkMakeNativeAPI() { api.pkSetSlotString_ptr = pkSetSlotString; api.pkSetSlotStringLength_ptr = pkSetSlotStringLength; api.pkSetSlotHandle_ptr = pkSetSlotHandle; + api.pkGetSlotHash_ptr = pkGetSlotHash; api.pkPlaceSelf_ptr = pkPlaceSelf; api.pkGetClass_ptr = pkGetClass; api.pkNewInstance_ptr = pkNewInstance; diff --git a/src/libs/std_io.c b/src/libs/std_io.c index 703cd60..1cd89c9 100644 --- a/src/libs/std_io.c +++ b/src/libs/std_io.c @@ -96,7 +96,7 @@ typedef struct { bool closed; // True if the file isn't closed yet. } File; -void* _newFile(PKVM* vm) { +void* _fileNew(PKVM* vm) { File* file = pkRealloc(vm, NULL, sizeof(File)); ASSERT(file != NULL, "pkRealloc failed."); file->closed = true; @@ -105,7 +105,7 @@ void* _newFile(PKVM* vm) { return file; } -void _deleteFile(PKVM* vm, void* ptr) { +void _fileDelete(PKVM* vm, void* ptr) { File* file = (File*)ptr; if (!file->closed) { ASSERT(file->fp != NULL, OOPS); @@ -440,7 +440,7 @@ void registerModuleIO(PKVM* vm) { pkModuleAddFunction(vm, io, "write", _ioWrite, 2); pkModuleAddFunction(vm, io, "flush", _ioFlush, 0); - PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _newFile, _deleteFile); + PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _fileNew, _fileDelete); pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1); pkClassAddMethod(vm, cls_file, "read", _fileRead, -1); pkClassAddMethod(vm, cls_file, "write", _fileWrite, 1); diff --git a/src/libs/std_os.c b/src/libs/std_os.c index 159ec87..728dd0f 100644 --- a/src/libs/std_os.c +++ b/src/libs/std_os.c @@ -97,6 +97,9 @@ PkHandle* osImportDL(PKVM* vm, void* handle) { } void osUnloadDL(PKVM* vm, void* handle) { + pkExportModuleFn cleanup_fn = \ + (pkExportModuleFn)GetProcAddress((HMODULE) handle, PK_CLEANUP_FN_NAME); + if (cleanup_fn != NULL) cleanup_fn(vm); FreeLibrary((HMODULE) handle); } diff --git a/src/libs/std_types.c b/src/libs/std_types.c index 535d8e4..2343701 100644 --- a/src/libs/std_types.c +++ b/src/libs/std_types.c @@ -8,16 +8,44 @@ #ifndef PK_AMALGAMATED #include "libs.h" +#include "../core/value.h" +#include "../core/vm.h" #endif +DEF(_typesHashable, + "types.hashable(value:Var) -> Bool\n" + "Returns true if the [value] is hashable.") { + + // Get argument 1 directly. + ASSERT(vm->fiber != NULL, OOPS); + ASSERT(1 < pkGetSlotsCount(vm), OOPS); + Var value = vm->fiber->ret[1]; + + if (!IS_OBJ(value)) pkSetSlotBool(vm, 0, true); + else pkSetSlotBool(vm, 0, isObjectHashable(AS_OBJ(value)->type)); +} + +DEF(_typesHash, + "types.hash(value:Var) -> Number\n" + "Returns the hash of the [value]") { + + // Get argument 1 directly. + ASSERT(vm->fiber != NULL, OOPS); + ASSERT(1 < pkGetSlotsCount(vm), OOPS); + Var value = vm->fiber->ret[1]; + + if (IS_OBJ(value) && !isObjectHashable(AS_OBJ(value)->type)) { + pkSetRuntimeErrorFmt(vm, "Type '%s' is not hashable.", varTypeName(value)); + return; + } + + pkSetSlotNumber(vm, 0, varHashValue(value)); +} + /*****************************************************************************/ /* BYTE BUFFER */ /*****************************************************************************/ -#ifndef PK_AMALGAMATED -#include "../core/value.h" -#endif - void* _bytebuffNew(PKVM* vm) { pkByteBuffer* self = pkRealloc(vm, NULL, sizeof(pkByteBuffer)); pkByteBufferInit(self); @@ -263,6 +291,9 @@ void _vectorRepr(PKVM* vm) { void registerModuleTypes(PKVM* vm) { PkHandle* types = pkNewModule(vm, "types"); + pkModuleAddFunction(vm, types, "hashable", _typesHashable, 1); + pkModuleAddFunction(vm, types, "hash", _typesHash, 1); + PkHandle* cls_byte_buffer = pkNewClass(vm, "ByteBuffer", NULL, types, _bytebuffNew, _bytebuffDelete); diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index c263d58..bdb0dfc 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -60,6 +60,13 @@ if a and b then assert(false) end if a or b then val = 42 else assert(false) end assert(val == 42) if get_true() or false then val = 12 end assert(val == 12) +if (get_true() or false) and ## New line after and. + ((a or b) or (a and b)) + assert(true) ## Reachable. +else + assert(false) ## Unreachable +end + ## Newer logical or implementation. ## a or b === if (a) return a else return b ## a and b === if (!a) return a else return b diff --git a/tests/native/dl/pknative.c b/tests/native/dl/pknative.c index b2c86be..76cdf9e 100644 --- a/tests/native/dl/pknative.c +++ b/tests/native/dl/pknative.c @@ -51,6 +51,7 @@ typedef void (*pkSetSlotNumber_t)(PKVM*, int, double); typedef void (*pkSetSlotString_t)(PKVM*, int, const char*); typedef void (*pkSetSlotStringLength_t)(PKVM*, int, const char*, uint32_t); typedef void (*pkSetSlotHandle_t)(PKVM*, int, PkHandle*); +typedef uint32_t (*pkGetSlotHash_t)(PKVM*, int); typedef void (*pkPlaceSelf_t)(PKVM*, int); typedef void (*pkGetClass_t)(PKVM*, int, int); typedef bool (*pkNewInstance_t)(PKVM*, int, int, int, int); @@ -110,6 +111,7 @@ typedef struct { pkSetSlotString_t pkSetSlotString_ptr; pkSetSlotStringLength_t pkSetSlotStringLength_ptr; pkSetSlotHandle_t pkSetSlotHandle_ptr; + pkGetSlotHash_t pkGetSlotHash_ptr; pkPlaceSelf_t pkPlaceSelf_ptr; pkGetClass_t pkGetClass_ptr; pkNewInstance_t pkNewInstance_ptr; @@ -172,6 +174,7 @@ PK_EXPORT void pkInitApi(PkNativeApi* api) { pk_api.pkSetSlotString_ptr = api->pkSetSlotString_ptr; pk_api.pkSetSlotStringLength_ptr = api->pkSetSlotStringLength_ptr; pk_api.pkSetSlotHandle_ptr = api->pkSetSlotHandle_ptr; + pk_api.pkGetSlotHash_ptr = api->pkGetSlotHash_ptr; pk_api.pkPlaceSelf_ptr = api->pkPlaceSelf_ptr; pk_api.pkGetClass_ptr = api->pkGetClass_ptr; pk_api.pkNewInstance_ptr = api->pkNewInstance_ptr; @@ -360,6 +363,10 @@ void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle) { pk_api.pkSetSlotHandle_ptr(vm, index, handle); } +uint32_t pkGetSlotHash(PKVM* vm, int index) { + return pk_api.pkGetSlotHash_ptr(vm, index); +} + void pkPlaceSelf(PKVM* vm, int index) { pk_api.pkPlaceSelf_ptr(vm, index); }