extension module implemented

now it's possible to import a dynamic libray (*.dll, *.so) in
a pocket script.
This commit is contained in:
Thakee Nathees 2022-05-30 22:53:24 +05:30
parent 3136eb4817
commit bd61e77593
23 changed files with 944 additions and 237 deletions

View File

@ -6,7 +6,7 @@ CC = gcc
CFLAGS = -fPIC
DEBUG_CFLAGS = -D DEBUG -g3 -Og
RELEASE_CFLAGS = -g -O3
LDFLAGS = -lm
LDFLAGS = -lm -ldl
TARGET_EXEC = pocket
BUILD_DIR = ./build/

View File

@ -68,7 +68,7 @@ except for a c99 compatible compiler. It can be compiled with the following comm
#### GCC / MinGw / Clang (alias with gcc)
```
gcc -o pocket cli/*.c src/core/*.c src/libs/*.c -Isrc/include -lm
gcc -o pocket cli/*.c src/core/*.c src/libs/*.c -Isrc/include -lm -ldl
```
#### MSVC
@ -93,10 +93,12 @@ for the MSVS installation path and setup the build environment.
### For other compiler/IDE
1. Create an empty project file / makefile.
2. Add all C files in the src directory.
3. Add all C files in the cli directory (**NOT** recursively).
4. Add `src/include` to include path.
5. Compile.
2. Add all C files in the src/core/ directory.
3. Add all C files in the src/libs/ directory.
4. Add all C files in the cli/ directory.
5. Add `src/include` to include path.
6. If \*nix link m, dl
7. Compile.
Visual studio project files can be generated with the premake, see
[scripts/README](https://github.com/ThakeeNathees/pocketlang/scripts/README.md)

View File

@ -1,48 +0,0 @@
##
## Copyright (c) 2020-2022 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
##
## A tiny script to download and place premake binary in this path.
## Primarly used to generate Visual Studio project files. Feel free
## add other build script and platforms.
import urllib.request
import os, platform
import tempfile, zipfile, tarfile
from os.path import abspath, dirname, join
THIS_PATH = abspath(dirname(__file__))
PREMAKE_PLATFORM_URL = {
"Windows": "https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-windows.zip",
#"Linux": TODO,
#"Darwin": TODO,
}
def main():
system = platform.system()
if system not in PREMAKE_PLATFORM_URL:
error_exit(f"Platform {system} is currently not supported.\n" +\
"(You can modify this script to add your platform and contribute).")
premake_url = PREMAKE_PLATFORM_URL[system]
tmpdir = tempfile.mkdtemp()
zip_path = join(tmpdir, 'premake5.zip')
with urllib.request.urlopen(premake_url) as binary_zip:
with open(zip_path, 'wb') as f:
f.write(binary_zip.read())
premake_zip = zipfile.ZipFile(zip_path, 'r')
premake_zip.extractall(THIS_PATH)
print("premake5 downloaded successfully.")
## prints an error message to stderr and exit immediately.
def error_exit(msg):
print("Error:", msg, file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@ -11,12 +11,12 @@ from os.path import (join, exists, abspath,
## the root path.
ROOT_PATH = abspath(join(dirname(__file__), "../"))
NATIVE_HEADER = "pknative.gen.h"
NATIVE_SOURCE = "nativeapi.gen.h"
NATIVE_API_EXT = "pknative.c"
NATIVE_API_IMP = "nativeapi.h"
POCKET_HEADER = join(ROOT_PATH, f"src/include/pocketlang.h")
TARGET_HEADER = join(ROOT_PATH, f"src/include/{NATIVE_HEADER}")
TARGET_SOURCE = join(ROOT_PATH, f"src/core/{NATIVE_SOURCE}")
TARGET_EXT = join(ROOT_PATH, f"tests/native/dl/{NATIVE_API_EXT}")
TARGET_IMP = join(ROOT_PATH, f"src/libs/gen/{NATIVE_API_IMP}")
DL_IMPLEMENT = 'PK_DL_IMPLEMENT'
PK_API = "pk_api"
@ -38,11 +38,7 @@ HEADER = f'''\
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef PK_AMALGAMATED
#include <pocketlang.h>%s
#endif
%s
// !! THIS FILE IS GENERATED DO NOT EDIT !!
'''
@ -135,18 +131,16 @@ def generate():
api_functions = get_api_functions()
## Generate pocket native header.
with open(TARGET_HEADER, 'w') as fp:
fp.write(HEADER % '')
with open(TARGET_EXT, 'w') as fp:
fp.write(HEADER % '\n#include <pocketlang.h>\n')
fp.write(fn_typedefs(api_functions))
fp.write(api_typedef(api_functions))
fp.write(f'\n#if defined({DL_IMPLEMENT})\n\n')
fp.write(init_api(api_functions))
fp.write(define_functions(api_functions))
fp.write(f'\n#endif //{DL_IMPLEMENT}\n')
## Generate native api source.
with open(TARGET_SOURCE, 'w') as fp:
fp.write(HEADER % '')
with open(TARGET_IMP, 'w') as fp:
fp.write(HEADER % '\n#ifndef PK_AMALGAMATED\n#include <pocketlang.h>\n#endif\n\n')
fp.write(fn_typedefs(api_functions))
fp.write(api_typedef(api_functions))
@ -163,5 +157,5 @@ def generate():
if __name__ == "__main__":
generate()
print("Generated:", relpath(TARGET_HEADER, ROOT_PATH))
print("Generated:", relpath(TARGET_SOURCE, ROOT_PATH))
print("Generated:", relpath(TARGET_EXT, ROOT_PATH))
print("Generated:", relpath(TARGET_IMP, ROOT_PATH))

View File

@ -1,98 +0,0 @@
##
## Copyright (c) 2020-2022 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
##
## A quick script to detect memory leaks, from the trace report.
## To get the trace report redefine TRACE_MEMORY as 1 at the
## pk_internal.h and compile pocketlang.
raise "This script Need refactor after removing pkAllocString " + \
"and adding pkRealloc"
import sys
def detect_leak():
trace_log_id = "[memory trace]"
total_bytes = 0 ## Totally allocated bytes.
mem = dict() ## key = address, value = bytes.
str_alloc_id = "[alloc string]"
strs = dict() ## string allocations.
trace_log_file_path = sys.argv[1]
with open(trace_log_file_path, 'r') as f:
for line in f.readlines():
if line.startswith(str_alloc_id):
line = line[len(trace_log_id) + 1:].strip()
type, data = split_and_strip(line, ':')
if type == "alloc":
addr, bytes = split_and_strip(data, '=')
bytes = int(bytes.replace(' bytes', ''))
strs[addr] = bytes
else: ## "dealloc"
addr = data.strip()
strs.pop(addr)
elif line.startswith(trace_log_id):
line = line[len(trace_log_id) + 1:].strip()
type, data = split_and_strip(line, ':')
addr, bytes = split_and_strip(data, '=')
bytes = bytes.replace(' bytes', '')
if type == "malloc":
bytes = int(bytes)
assert(bytes >= 0); total_bytes += bytes
mem[addr] = bytes
elif type == "free":
bytes = int(bytes)
assert(bytes <= 0); total_bytes += bytes
mem.pop(addr)
elif type == "realloc":
oldp, newp = split_and_strip(addr, '->')
olds, news = split_and_strip(bytes, '->')
olds = int(olds); news = int(news)
total_bytes += (news - olds)
assert(mem[oldp] == olds)
mem.pop(oldp)
mem[newp] = news
success = True
if total_bytes != 0:
print_err(f"Memory leak detected - {total_bytes} bytes were never freed.")
success = False
if len(mem) != 0:
print_err("Memory leak detected - some addresses were never freed.")
for addr in mem:
print(f" {addr} : {mem[addr]} bytes")
success = False
if len(strs) != 0:
print_err("Memory leak detected - string allocation(s) were never freed.")
for addr in strs:
print(f" {addr} : {strs[addr]} bytes")
success = False
if success:
print("No leaks were detected.")
else:
sys.exit(1)
def split_and_strip(string, delim):
return map(lambda s: s.strip(), string.split(delim))
def print_err(msg):
print("Error:", msg, file=sys.stderr)
if __name__ == "__main__":
detect_leak()

View File

@ -1 +1,18 @@
@premake5 vs2019
@echo off
pushd %cd%
cd %~dp0
:: unzip.exe comes with git for windows.
if not exist premake5.exe (
echo premake5.exe not exists, downloading
echo.
curl -L https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-windows.zip --output premake5.zip
unzip premake5.zip && premake5.zip
echo.
)
premake5 vs2019
popd

View File

@ -51,10 +51,6 @@
// Dump the stack values and the globals.
#define DUMP_STACK 0
// Trace memory allocations. Enable this and redirect the trace dump to a file
// and run the script leak_detect.py to check for memory leaks.
#define TRACE_MEMORY 0
// Nan-Tagging could be disable for debugging/portability purposes. See "var.h"
// header for more information on Nan-tagging.
#define VAR_NAN_TAGGING 1

View File

@ -17,7 +17,7 @@
#include "vm.h"
#endif
// TODO: Document this or Find a better way.
// FIXME: Document this or Find a better way.
//
// Pocketlang core doesn't implement path resolving funcionality. Rather it
// should be provided the host application. By default we're using an
@ -32,6 +32,13 @@
void registerLibs(PKVM* vm);
void cleanupLibs(PKVM* vm);
char* pathResolveImport(PKVM* vm, const char* from, const char* path);
#ifndef PK_NO_DL
void* osLoadDL(PKVM* vm, const char* path);
PkHandle* osImportDL(PKVM* vm, void* handle);
void osUnloadDL(PKVM* vm, void* handle);
#endif
#endif
#define CHECK_ARG_NULL(name) \
@ -81,15 +88,8 @@ static char* stdinRead(PKVM* vm);
static char* loadScript(PKVM* vm, const char* path);
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
#if TRACE_MEMORY
void* newptr = vm->config.realloc_fn(ptr, size, vm->config.user_data);
printf("[pkRealloc] %p -> %p %+li bytes\n", ptr, newptr, (long) size);
return ptr;
#else
return vm->config.realloc_fn(ptr, size, vm->config.user_data);
#endif
}
PkConfiguration pkNewConfiguration() {
@ -103,6 +103,13 @@ PkConfiguration pkNewConfiguration() {
config.stdin_read = stdinRead;
#ifndef PK_NO_LIBS
config.resolve_path_fn = pathResolveImport;
#ifndef PK_NO_DL
config.load_dl_fn = osLoadDL;
config.import_dl_fn = osImportDL;
config.unload_dl_fn = osUnloadDL;
#endif
#endif
config.load_script_fn = loadScript;

View File

@ -1143,6 +1143,9 @@ void freeObject(PKVM* vm, Object* self) {
pkVarBufferClear(&module->globals, vm);
pkUintBufferClear(&module->global_names, vm);
pkVarBufferClear(&module->constants, vm);
#ifndef PK_NO_DL
if (module->handle) vmUnloadDlHandle(vm, module->handle);
#endif
DEALLOCATE(vm, self, Module);
return;
}

View File

@ -311,6 +311,13 @@ struct Module {
// will be set to true. If a module doesn't have globals, We can safely set
// it to true to prevent from running the above body function, if it has one.
bool initialized;
#ifndef PK_NO_DL
// If the module loaded from a native extension, this handle will reference
// to the platform dependent handle of that module and will be released
// when the module garbage collected.
void* handle;
#endif
};
// A struct contain opcodes and other information of a compiled function.

View File

@ -47,39 +47,7 @@ void* vmRealloc(PKVM* vm, void* memory, size_t old_size, size_t new_size) {
vm->collecting_garbage = false;
}
#if TRACE_MEMORY
void* ptr = vm->config.realloc_fn(memory, new_size, vm->config.user_data);
do {
// Deallocation of the VM itself cannot be traced.
if (memory == vm) break;
if (memory == NULL && new_size == 0) { //< Just nothing.
ASSERT(old_size == 0, OOPS);
break;
}
if (old_size == 0 && new_size > 0) { // New allocation.
ASSERT(memory == NULL, OOPS);
printf("[memory trace] malloc : %p = %+li bytes\n",
ptr, (long) new_size);
} else if (new_size == 0) { // Free.
ASSERT(memory != NULL && old_size != 0, OOPS);
printf("[memory trace] free : %p = -%li bytes\n",
memory, (long) old_size);
} else { // Realloc.
ASSERT(old_size != 0 && new_size != 0 && memory != NULL, OOPS);
printf("[memory trace] realloc : %p -> %p = %+li -> %+li bytes\n",
memory, ptr, (long) (old_size), (long) (new_size));
}
} while (false);
return ptr;
#else
return vm->config.realloc_fn(memory, new_size, vm->config.user_data);
#endif
}
void vmPushTempRef(PKVM* vm, Object* obj) {
@ -368,6 +336,68 @@ PkResult vmCallFunction(PKVM* vm, Closure* fn, int argc, Var* argv, Var* ret) {
return vmCallMethod(vm, VAR_UNDEFINED, fn, argc, argv, ret);
}
#ifndef PK_NO_DL
// Returns true if the path ends with ".dll" or ".so".
static bool _isPathDL(String* path) {
const char* dlext[] = {
".so",
".dll",
NULL,
};
for (const char** ext = dlext; *ext != NULL; ext++) {
const char* start = path->data + (path->length - strlen(*ext));
if (!strncmp(start, *ext, strlen(*ext))) return true;
}
return false;
}
static Module* _importDL(PKVM* vm, String* resolved, String* name) {
if (vm->config.import_dl_fn == NULL) {
VM_SET_ERROR(vm, newString(vm, "Dynamic library importer not provided."));
return NULL;
}
ASSERT(vm->config.load_dl_fn != NULL, OOPS);
void* handle = vm->config.load_dl_fn(vm, resolved->data);
if (handle == NULL) {
VM_SET_ERROR(vm, stringFormat(vm, "Error loading module at \"@\"",
resolved));
return NULL;
}
PkHandle* pkhandle = vm->config.import_dl_fn(vm, handle);
if (pkhandle == NULL) {
VM_SET_ERROR(vm, stringFormat(vm, "Error loading module at \"@\"",
resolved));
return NULL;
}
if (!IS_OBJ_TYPE(pkhandle->value, OBJ_MODULE)) {
VM_SET_ERROR(vm, stringFormat(vm, "Returned handle wasn't a "
"module at \"@\"", resolved));
return NULL;
}
Module* module = (Module*) AS_OBJ(pkhandle->value);
module->name = name;
module->path = resolved;
module->handle = handle;
vmRegisterModule(vm, module, resolved);
pkReleaseHandle(vm, pkhandle);
return module;
}
void vmUnloadDlHandle(PKVM* vm, void* handle) {
if (handle && vm->config.unload_dl_fn)
vm->config.unload_dl_fn(vm, handle);
}
#endif // PK_NO_DL
/*****************************************************************************/
/* VM INTERNALS */
/*****************************************************************************/
@ -460,7 +490,14 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
// The script not exists in the VM, make sure we have the script loading
// api function.
#ifndef PK_NO_DL
bool isdl = _isPathDL(resolved);
if (isdl && vm->config.load_dl_fn == NULL
|| vm->config.load_script_fn == NULL) {
#else
if (vm->config.load_script_fn == NULL) {
#endif
VM_SET_ERROR(vm, newString(vm, "Cannot import. The hosting application "
"haven't registered the module loading API"));
return VAR_NULL;
@ -485,7 +522,13 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
}
_name->hash = utilHashString(_name->data);
vmPushTempRef(vm, &_name->_super); // _name.
#ifndef PK_NO_DL
if (isdl) module = _importDL(vm, resolved, _name);
else /* ... */
#endif
module = _importScript(vm, resolved, _name);
vmPopTempRef(vm); // _name.
}
vmPopTempRef(vm); // resolved.

View File

@ -248,4 +248,11 @@ PkResult vmCallMethod(PKVM* vm, Var self, Closure* fn,
// On failure, it'll set an error and return VAR_NULL.
Var vmImportModule(PKVM* vm, String* from, String* path);
#ifndef PK_NO_DL
// Release platform dependent native extension module handle. (*.dll, *.so).
void vmUnloadDlHandle(PKVM* vm, void* handle);
#endif
#endif // PK_VM_H

View File

@ -109,6 +109,24 @@ typedef void (*pkSignalFn) (void*);
// the VM will claim the ownership of the string.
typedef char* (*pkLoadScriptFn) (PKVM* vm, const char* path);
#ifndef PK_NO_DL
// Load and return the native extension (*.dll, *.so) from the path, this will
// then used to import the module with the pkImportImportDL function. On error
// the function should return NULL and shouldn't use any error api function.
typedef void* (*pkLoadDL) (PKVM* vm, const char* path);
// Native extension loader from the dynamic library. The handle should be vaiid
// as long as the module handle is alive. On error the function should return
// NULL and shouldn't use any error api function.
typedef PkHandle* (*pkImportDL) (PKVM* vm, void* handle);
// Once the native module is gargage collected, the dl handle will be released
// with pkUnloadDL function.
typedef void (*pkUnloadDL) (PKVM* vm, void* handle);
#endif // PK_NO_DL
// A function callback to resolve the import statement path. [from] path can
// be either path to a script or a directory or NULL if [path] is relative to
// cwd. If the path is a directory it'll always ends with a path separator
@ -189,6 +207,12 @@ struct PkConfiguration {
pkResolvePathFn resolve_path_fn;
pkLoadScriptFn load_script_fn;
#ifndef PK_NO_DL
pkLoadDL load_dl_fn;
pkImportDL import_dl_fn;
pkUnloadDL unload_dl_fn;
#endif
// If true stderr calls will use ansi color codes.
bool use_ansi_escape;

205
src/libs/gen/nativeapi.h Normal file
View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef PK_AMALGAMATED
#include <pocketlang.h>
#endif
// !! THIS FILE IS GENERATED DO NOT EDIT !!
typedef PkConfiguration (*pkNewConfiguration_t)();
typedef PKVM* (*pkNewVM_t)(PkConfiguration*);
typedef void (*pkFreeVM_t)(PKVM*);
typedef void (*pkSetUserData_t)(PKVM*, void*);
typedef void* (*pkGetUserData_t)(const PKVM*);
typedef void (*pkRegisterBuiltinFn_t)(PKVM*, const char*, pkNativeFn, int, const char*);
typedef void (*pkAddSearchPath_t)(PKVM*, const char*);
typedef void* (*pkRealloc_t)(PKVM*, void*, size_t);
typedef void (*pkReleaseHandle_t)(PKVM*, PkHandle*);
typedef PkHandle* (*pkNewModule_t)(PKVM*, const char*);
typedef void (*pkRegisterModule_t)(PKVM*, PkHandle*);
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn);
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
typedef void (*pkModuleAddSource_t)(PKVM*, PkHandle*, const char*);
typedef PkResult (*pkRunString_t)(PKVM*, const char*);
typedef PkResult (*pkRunFile_t)(PKVM*, const char*);
typedef PkResult (*pkRunREPL_t)(PKVM*);
typedef void (*pkSetRuntimeError_t)(PKVM*, const char*);
typedef void* (*pkGetSelf_t)(const PKVM*);
typedef int (*pkGetArgc_t)(const PKVM*);
typedef bool (*pkCheckArgcRange_t)(PKVM*, int, int, int);
typedef bool (*pkValidateSlotBool_t)(PKVM*, int, bool*);
typedef bool (*pkValidateSlotNumber_t)(PKVM*, int, double*);
typedef bool (*pkValidateSlotInteger_t)(PKVM*, int, int32_t*);
typedef bool (*pkValidateSlotString_t)(PKVM*, int, const char**, uint32_t*);
typedef bool (*pkValidateSlotType_t)(PKVM*, int, PkVarType);
typedef bool (*pkValidateSlotInstanceOf_t)(PKVM*, int, int);
typedef bool (*pkIsSlotInstanceOf_t)(PKVM*, int, int, bool*);
typedef void (*pkReserveSlots_t)(PKVM*, int);
typedef int (*pkGetSlotsCount_t)(PKVM*);
typedef PkVarType (*pkGetSlotType_t)(PKVM*, int);
typedef bool (*pkGetSlotBool_t)(PKVM*, int);
typedef double (*pkGetSlotNumber_t)(PKVM*, int);
typedef const char* (*pkGetSlotString_t)(PKVM*, int, uint32_t*);
typedef PkHandle* (*pkGetSlotHandle_t)(PKVM*, int);
typedef void* (*pkGetSlotNativeInstance_t)(PKVM*, int);
typedef void (*pkSetSlotNull_t)(PKVM*, int);
typedef void (*pkSetSlotBool_t)(PKVM*, int, bool);
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 void (*pkPlaceSelf_t)(PKVM*, int);
typedef void (*pkGetClass_t)(PKVM*, int, int);
typedef bool (*pkNewInstance_t)(PKVM*, int, int, int, int);
typedef void (*pkNewRange_t)(PKVM*, int, double, double);
typedef void (*pkNewList_t)(PKVM*, int);
typedef void (*pkNewMap_t)(PKVM*, int);
typedef bool (*pkListInsert_t)(PKVM*, int, int32_t, int);
typedef bool (*pkListPop_t)(PKVM*, int, int32_t, int);
typedef uint32_t (*pkListLength_t)(PKVM*, int);
typedef bool (*pkCallFunction_t)(PKVM*, int, int, int, int);
typedef bool (*pkCallMethod_t)(PKVM*, int, const char*, int, int, int);
typedef bool (*pkGetAttribute_t)(PKVM*, int, const char*, int);
typedef bool (*pkSetAttribute_t)(PKVM*, int, const char*, int);
typedef bool (*pkImportModule_t)(PKVM*, const char*, int);
typedef struct {
pkNewConfiguration_t pkNewConfiguration_ptr;
pkNewVM_t pkNewVM_ptr;
pkFreeVM_t pkFreeVM_ptr;
pkSetUserData_t pkSetUserData_ptr;
pkGetUserData_t pkGetUserData_ptr;
pkRegisterBuiltinFn_t pkRegisterBuiltinFn_ptr;
pkAddSearchPath_t pkAddSearchPath_ptr;
pkRealloc_t pkRealloc_ptr;
pkReleaseHandle_t pkReleaseHandle_ptr;
pkNewModule_t pkNewModule_ptr;
pkRegisterModule_t pkRegisterModule_ptr;
pkModuleAddFunction_t pkModuleAddFunction_ptr;
pkNewClass_t pkNewClass_ptr;
pkClassAddMethod_t pkClassAddMethod_ptr;
pkModuleAddSource_t pkModuleAddSource_ptr;
pkRunString_t pkRunString_ptr;
pkRunFile_t pkRunFile_ptr;
pkRunREPL_t pkRunREPL_ptr;
pkSetRuntimeError_t pkSetRuntimeError_ptr;
pkGetSelf_t pkGetSelf_ptr;
pkGetArgc_t pkGetArgc_ptr;
pkCheckArgcRange_t pkCheckArgcRange_ptr;
pkValidateSlotBool_t pkValidateSlotBool_ptr;
pkValidateSlotNumber_t pkValidateSlotNumber_ptr;
pkValidateSlotInteger_t pkValidateSlotInteger_ptr;
pkValidateSlotString_t pkValidateSlotString_ptr;
pkValidateSlotType_t pkValidateSlotType_ptr;
pkValidateSlotInstanceOf_t pkValidateSlotInstanceOf_ptr;
pkIsSlotInstanceOf_t pkIsSlotInstanceOf_ptr;
pkReserveSlots_t pkReserveSlots_ptr;
pkGetSlotsCount_t pkGetSlotsCount_ptr;
pkGetSlotType_t pkGetSlotType_ptr;
pkGetSlotBool_t pkGetSlotBool_ptr;
pkGetSlotNumber_t pkGetSlotNumber_ptr;
pkGetSlotString_t pkGetSlotString_ptr;
pkGetSlotHandle_t pkGetSlotHandle_ptr;
pkGetSlotNativeInstance_t pkGetSlotNativeInstance_ptr;
pkSetSlotNull_t pkSetSlotNull_ptr;
pkSetSlotBool_t pkSetSlotBool_ptr;
pkSetSlotNumber_t pkSetSlotNumber_ptr;
pkSetSlotString_t pkSetSlotString_ptr;
pkSetSlotStringLength_t pkSetSlotStringLength_ptr;
pkSetSlotHandle_t pkSetSlotHandle_ptr;
pkPlaceSelf_t pkPlaceSelf_ptr;
pkGetClass_t pkGetClass_ptr;
pkNewInstance_t pkNewInstance_ptr;
pkNewRange_t pkNewRange_ptr;
pkNewList_t pkNewList_ptr;
pkNewMap_t pkNewMap_ptr;
pkListInsert_t pkListInsert_ptr;
pkListPop_t pkListPop_ptr;
pkListLength_t pkListLength_ptr;
pkCallFunction_t pkCallFunction_ptr;
pkCallMethod_t pkCallMethod_ptr;
pkGetAttribute_t pkGetAttribute_ptr;
pkSetAttribute_t pkSetAttribute_ptr;
pkImportModule_t pkImportModule_ptr;
} PkNativeApi;
#define PK_API_INIT_FN_NAME "pkInitApi"
#define PK_EXPORT_FN_NAME "pkExportModule"
typedef void (*pkInitApiFn)(PkNativeApi*);
typedef PkHandle* (*pkExportModuleFn)(PKVM*);
#ifdef PK_DL_IMPLEMENT
PkNativeApi pkMakeNativeAPI() {
PkNativeApi api;
api.pkNewConfiguration_ptr = pkNewConfiguration;
api.pkNewVM_ptr = pkNewVM;
api.pkFreeVM_ptr = pkFreeVM;
api.pkSetUserData_ptr = pkSetUserData;
api.pkGetUserData_ptr = pkGetUserData;
api.pkRegisterBuiltinFn_ptr = pkRegisterBuiltinFn;
api.pkAddSearchPath_ptr = pkAddSearchPath;
api.pkRealloc_ptr = pkRealloc;
api.pkReleaseHandle_ptr = pkReleaseHandle;
api.pkNewModule_ptr = pkNewModule;
api.pkRegisterModule_ptr = pkRegisterModule;
api.pkModuleAddFunction_ptr = pkModuleAddFunction;
api.pkNewClass_ptr = pkNewClass;
api.pkClassAddMethod_ptr = pkClassAddMethod;
api.pkModuleAddSource_ptr = pkModuleAddSource;
api.pkRunString_ptr = pkRunString;
api.pkRunFile_ptr = pkRunFile;
api.pkRunREPL_ptr = pkRunREPL;
api.pkSetRuntimeError_ptr = pkSetRuntimeError;
api.pkGetSelf_ptr = pkGetSelf;
api.pkGetArgc_ptr = pkGetArgc;
api.pkCheckArgcRange_ptr = pkCheckArgcRange;
api.pkValidateSlotBool_ptr = pkValidateSlotBool;
api.pkValidateSlotNumber_ptr = pkValidateSlotNumber;
api.pkValidateSlotInteger_ptr = pkValidateSlotInteger;
api.pkValidateSlotString_ptr = pkValidateSlotString;
api.pkValidateSlotType_ptr = pkValidateSlotType;
api.pkValidateSlotInstanceOf_ptr = pkValidateSlotInstanceOf;
api.pkIsSlotInstanceOf_ptr = pkIsSlotInstanceOf;
api.pkReserveSlots_ptr = pkReserveSlots;
api.pkGetSlotsCount_ptr = pkGetSlotsCount;
api.pkGetSlotType_ptr = pkGetSlotType;
api.pkGetSlotBool_ptr = pkGetSlotBool;
api.pkGetSlotNumber_ptr = pkGetSlotNumber;
api.pkGetSlotString_ptr = pkGetSlotString;
api.pkGetSlotHandle_ptr = pkGetSlotHandle;
api.pkGetSlotNativeInstance_ptr = pkGetSlotNativeInstance;
api.pkSetSlotNull_ptr = pkSetSlotNull;
api.pkSetSlotBool_ptr = pkSetSlotBool;
api.pkSetSlotNumber_ptr = pkSetSlotNumber;
api.pkSetSlotString_ptr = pkSetSlotString;
api.pkSetSlotStringLength_ptr = pkSetSlotStringLength;
api.pkSetSlotHandle_ptr = pkSetSlotHandle;
api.pkPlaceSelf_ptr = pkPlaceSelf;
api.pkGetClass_ptr = pkGetClass;
api.pkNewInstance_ptr = pkNewInstance;
api.pkNewRange_ptr = pkNewRange;
api.pkNewList_ptr = pkNewList;
api.pkNewMap_ptr = pkNewMap;
api.pkListInsert_ptr = pkListInsert;
api.pkListPop_ptr = pkListPop;
api.pkListLength_ptr = pkListLength;
api.pkCallFunction_ptr = pkCallFunction;
api.pkCallMethod_ptr = pkCallMethod;
api.pkGetAttribute_ptr = pkGetAttribute;
api.pkSetAttribute_ptr = pkSetAttribute;
api.pkImportModule_ptr = pkImportModule;
return api;
}
#endif // PK_DL_IMPLEMENT

View File

@ -51,6 +51,19 @@ void cleanupLibs(PKVM* vm);
// inorder to use the import statements.
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
#ifndef PK_NO_DL
// Loads the platform dependent dynamic library and returns the handle.
void* osLoadDL(PKVM* vm, const char* path);
// Import the module from the dynamic library handle which was loaded from os.
PkHandle* osImportDL(PKVM* vm, void* handle);
// Release the dynamic library.
void osUnloadDL(PKVM* vm, void* handle);
#endif
// Write the executable's path to the buffer and return true, if it failed
// it'll return false.
bool osGetExeFilePath(char* buff, int size);

View File

@ -29,21 +29,20 @@
#define _PKOS_LINUX_
#define OS_NAME "linux"
#elif defined(__unix__)
#define _PKOS_UNIX_
#define OS_NAME "unix"
#elif defined(_POSIX_VERSION)
#define _PKOS_POSIX_
#define OS_NAME "posix"
#else
#define _PKOS_UNKNOWN_
#define OS_NAME "<?>"
#endif
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
#if defined(_PKOS_WIN_)
#include <windows.h>
#endif
#if defined(__linux__) && !defined(PK_NO_DL)
#include <dlfcn.h>
#endif
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
#include <direct.h>
#include <io.h>
@ -65,6 +64,88 @@
// See: https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
#define MAX_PATH_LEN 4096
#ifndef PK_NO_DL
#define PK_DL_IMPLEMENT
#include "gen/nativeapi.h" //<< AMALG_INLINE >>
#ifdef _PKOS_WIN_
void* osLoadDL(PKVM* vm, const char* path) {
HMODULE handle = LoadLibraryA(path);
if (handle == NULL) return NULL;
pkInitApiFn init_fn = \
(pkInitApiFn) GetProcAddress(handle, PK_API_INIT_FN_NAME);
if (init_fn == NULL) {
FreeLibrary(handle);
return NULL;
}
PkNativeApi api = pkMakeNativeAPI();
init_fn(&api);
return (void*) handle;
}
PkHandle* osImportDL(PKVM* vm, void* handle) {
pkExportModuleFn export_fn = \
(pkExportModuleFn)GetProcAddress((HMODULE) handle, PK_EXPORT_FN_NAME);
if (export_fn == NULL) return NULL;
return export_fn(vm);
}
void osUnloadDL(PKVM* vm, void* handle) {
FreeLibrary((HMODULE) handle);
}
#elif defined(__linux__)
void* osLoadDL(PKVM* vm, const char* path) {
// https://man7.org/linux/man-pages/man3/dlopen.3.html
void* handle = dlopen(path, RTLD_LAZY);
if (handle == NULL) return NULL;
pkInitApiFn init_fn = dlsym(handle, PK_API_INIT_FN_NAME);
if (init_fn == NULL) {
if (dlclose(handle)) { /* TODO: Handle error. */ }
dlerror(); // Clear error.
return NULL;
}
PkNativeApi api = pkMakeNativeAPI();
init_fn(&api);
return handle;
}
PkHandle* osImportDL(PKVM* vm, void* handle) {
pkExportModuleFn export_fn = dlsym(handle, PK_EXPORT_FN_NAME);
if (export_fn == NULL) {
dlerror(); // Clear error.
return NULL;
}
PkHandle* module = export_fn(vm);
dlerror(); // Clear error.
return module;
}
void osUnloadDL(PKVM* vm, void* handle) {
dlclose(handle);
}
#else
void* osLoadDL(PKVM* vm, const char* path) { return NULL; }
PkHandle* osImportDL(PKVM* vm, void* handle) { return NULL; }
void osUnloadDL(PKVM* vm, void* handle) { }
#endif
#endif // PK_NO_DL
bool osGetExeFilePath(char* buff, int size) {
#if defined(_PKOS_WIN_)

View File

@ -97,6 +97,13 @@ static char* tryImportPaths(PKVM* vm, char* path, char* buff) {
"",
".pk",
"/_init.pk",
#ifndef PK_NO_DL
#ifdef _WIN32
".dll",
#else
".so",
#endif
#endif
NULL, // Sentinal to mark the array end.
};
@ -382,15 +389,10 @@ void _registerSearchPaths(PKVM* vm) {
buff[length++] = last;
}
buff[length] = '\0';
pkAddSearchPath(vm, buff);
// FIXME: the bellow code is hard coded.
if (length + strlen("libs/") < MAX_PATH_LEN) {
strcpy(buff + length, (ps == CWK_STYLE_WINDOWS) ? "libs\\" : "libs/");
pkAddSearchPath(vm, buff);
}
ASSERT(length + strlen("libs/") < MAX_PATH_LEN, OOPS);
strcpy(buff + length, (ps == CWK_STYLE_WINDOWS) ? "libs\\" : "libs/");
pkAddSearchPath(vm, buff);
}
void registerModulePath(PKVM* vm) {

14
tests/native/dl/README.md Normal file
View File

@ -0,0 +1,14 @@
## Example on how compile a native extension.
#### MSVC
```
cl /LD mylib.c pknative.c /I../../../src/include/
rm *.obj *.exp *.lib
```
#### GCC
```
gcc -fPIC -c mylib.c pknative.c -I../../../src/include/
gcc -shared -o mylib.so mylib.o pknative.o
rm *.o
```

9
tests/native/dl/main.pk Normal file
View File

@ -0,0 +1,9 @@
## Import the native extension module.
## from either mylib.so, or mylib.dll
import mylib
if __name__ == "__main__"
## Call the registered function.
print('mylib.hello() = ${mylib.hello()}')
end

14
tests/native/dl/mylib.c Normal file
View File

@ -0,0 +1,14 @@
#include <pocketlang.h>
PK_EXPORT void hello(PKVM* vm) {
pkSetSlotString(vm, 0, "hello from dynamic lib.");
}
PK_EXPORT PkHandle* pkExportModule(PKVM* vm) {
PkHandle* mylib = pkNewModule(vm, "mylib");
pkModuleAddFunction(vm, mylib, "hello", hello, 0);
return mylib;
}

417
tests/native/dl/pknative.c Normal file
View File

@ -0,0 +1,417 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#include <pocketlang.h>
// !! THIS FILE IS GENERATED DO NOT EDIT !!
typedef PkConfiguration (*pkNewConfiguration_t)();
typedef PKVM* (*pkNewVM_t)(PkConfiguration*);
typedef void (*pkFreeVM_t)(PKVM*);
typedef void (*pkSetUserData_t)(PKVM*, void*);
typedef void* (*pkGetUserData_t)(const PKVM*);
typedef void (*pkRegisterBuiltinFn_t)(PKVM*, const char*, pkNativeFn, int, const char*);
typedef void (*pkAddSearchPath_t)(PKVM*, const char*);
typedef void* (*pkRealloc_t)(PKVM*, void*, size_t);
typedef void (*pkReleaseHandle_t)(PKVM*, PkHandle*);
typedef PkHandle* (*pkNewModule_t)(PKVM*, const char*);
typedef void (*pkRegisterModule_t)(PKVM*, PkHandle*);
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn);
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
typedef void (*pkModuleAddSource_t)(PKVM*, PkHandle*, const char*);
typedef PkResult (*pkRunString_t)(PKVM*, const char*);
typedef PkResult (*pkRunFile_t)(PKVM*, const char*);
typedef PkResult (*pkRunREPL_t)(PKVM*);
typedef void (*pkSetRuntimeError_t)(PKVM*, const char*);
typedef void* (*pkGetSelf_t)(const PKVM*);
typedef int (*pkGetArgc_t)(const PKVM*);
typedef bool (*pkCheckArgcRange_t)(PKVM*, int, int, int);
typedef bool (*pkValidateSlotBool_t)(PKVM*, int, bool*);
typedef bool (*pkValidateSlotNumber_t)(PKVM*, int, double*);
typedef bool (*pkValidateSlotInteger_t)(PKVM*, int, int32_t*);
typedef bool (*pkValidateSlotString_t)(PKVM*, int, const char**, uint32_t*);
typedef bool (*pkValidateSlotType_t)(PKVM*, int, PkVarType);
typedef bool (*pkValidateSlotInstanceOf_t)(PKVM*, int, int);
typedef bool (*pkIsSlotInstanceOf_t)(PKVM*, int, int, bool*);
typedef void (*pkReserveSlots_t)(PKVM*, int);
typedef int (*pkGetSlotsCount_t)(PKVM*);
typedef PkVarType (*pkGetSlotType_t)(PKVM*, int);
typedef bool (*pkGetSlotBool_t)(PKVM*, int);
typedef double (*pkGetSlotNumber_t)(PKVM*, int);
typedef const char* (*pkGetSlotString_t)(PKVM*, int, uint32_t*);
typedef PkHandle* (*pkGetSlotHandle_t)(PKVM*, int);
typedef void* (*pkGetSlotNativeInstance_t)(PKVM*, int);
typedef void (*pkSetSlotNull_t)(PKVM*, int);
typedef void (*pkSetSlotBool_t)(PKVM*, int, bool);
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 void (*pkPlaceSelf_t)(PKVM*, int);
typedef void (*pkGetClass_t)(PKVM*, int, int);
typedef bool (*pkNewInstance_t)(PKVM*, int, int, int, int);
typedef void (*pkNewRange_t)(PKVM*, int, double, double);
typedef void (*pkNewList_t)(PKVM*, int);
typedef void (*pkNewMap_t)(PKVM*, int);
typedef bool (*pkListInsert_t)(PKVM*, int, int32_t, int);
typedef bool (*pkListPop_t)(PKVM*, int, int32_t, int);
typedef uint32_t (*pkListLength_t)(PKVM*, int);
typedef bool (*pkCallFunction_t)(PKVM*, int, int, int, int);
typedef bool (*pkCallMethod_t)(PKVM*, int, const char*, int, int, int);
typedef bool (*pkGetAttribute_t)(PKVM*, int, const char*, int);
typedef bool (*pkSetAttribute_t)(PKVM*, int, const char*, int);
typedef bool (*pkImportModule_t)(PKVM*, const char*, int);
typedef struct {
pkNewConfiguration_t pkNewConfiguration_ptr;
pkNewVM_t pkNewVM_ptr;
pkFreeVM_t pkFreeVM_ptr;
pkSetUserData_t pkSetUserData_ptr;
pkGetUserData_t pkGetUserData_ptr;
pkRegisterBuiltinFn_t pkRegisterBuiltinFn_ptr;
pkAddSearchPath_t pkAddSearchPath_ptr;
pkRealloc_t pkRealloc_ptr;
pkReleaseHandle_t pkReleaseHandle_ptr;
pkNewModule_t pkNewModule_ptr;
pkRegisterModule_t pkRegisterModule_ptr;
pkModuleAddFunction_t pkModuleAddFunction_ptr;
pkNewClass_t pkNewClass_ptr;
pkClassAddMethod_t pkClassAddMethod_ptr;
pkModuleAddSource_t pkModuleAddSource_ptr;
pkRunString_t pkRunString_ptr;
pkRunFile_t pkRunFile_ptr;
pkRunREPL_t pkRunREPL_ptr;
pkSetRuntimeError_t pkSetRuntimeError_ptr;
pkGetSelf_t pkGetSelf_ptr;
pkGetArgc_t pkGetArgc_ptr;
pkCheckArgcRange_t pkCheckArgcRange_ptr;
pkValidateSlotBool_t pkValidateSlotBool_ptr;
pkValidateSlotNumber_t pkValidateSlotNumber_ptr;
pkValidateSlotInteger_t pkValidateSlotInteger_ptr;
pkValidateSlotString_t pkValidateSlotString_ptr;
pkValidateSlotType_t pkValidateSlotType_ptr;
pkValidateSlotInstanceOf_t pkValidateSlotInstanceOf_ptr;
pkIsSlotInstanceOf_t pkIsSlotInstanceOf_ptr;
pkReserveSlots_t pkReserveSlots_ptr;
pkGetSlotsCount_t pkGetSlotsCount_ptr;
pkGetSlotType_t pkGetSlotType_ptr;
pkGetSlotBool_t pkGetSlotBool_ptr;
pkGetSlotNumber_t pkGetSlotNumber_ptr;
pkGetSlotString_t pkGetSlotString_ptr;
pkGetSlotHandle_t pkGetSlotHandle_ptr;
pkGetSlotNativeInstance_t pkGetSlotNativeInstance_ptr;
pkSetSlotNull_t pkSetSlotNull_ptr;
pkSetSlotBool_t pkSetSlotBool_ptr;
pkSetSlotNumber_t pkSetSlotNumber_ptr;
pkSetSlotString_t pkSetSlotString_ptr;
pkSetSlotStringLength_t pkSetSlotStringLength_ptr;
pkSetSlotHandle_t pkSetSlotHandle_ptr;
pkPlaceSelf_t pkPlaceSelf_ptr;
pkGetClass_t pkGetClass_ptr;
pkNewInstance_t pkNewInstance_ptr;
pkNewRange_t pkNewRange_ptr;
pkNewList_t pkNewList_ptr;
pkNewMap_t pkNewMap_ptr;
pkListInsert_t pkListInsert_ptr;
pkListPop_t pkListPop_ptr;
pkListLength_t pkListLength_ptr;
pkCallFunction_t pkCallFunction_ptr;
pkCallMethod_t pkCallMethod_ptr;
pkGetAttribute_t pkGetAttribute_ptr;
pkSetAttribute_t pkSetAttribute_ptr;
pkImportModule_t pkImportModule_ptr;
} PkNativeApi;
static PkNativeApi pk_api;
PK_EXPORT void pkInitApi(PkNativeApi* api) {
pk_api.pkNewConfiguration_ptr = api->pkNewConfiguration_ptr;
pk_api.pkNewVM_ptr = api->pkNewVM_ptr;
pk_api.pkFreeVM_ptr = api->pkFreeVM_ptr;
pk_api.pkSetUserData_ptr = api->pkSetUserData_ptr;
pk_api.pkGetUserData_ptr = api->pkGetUserData_ptr;
pk_api.pkRegisterBuiltinFn_ptr = api->pkRegisterBuiltinFn_ptr;
pk_api.pkAddSearchPath_ptr = api->pkAddSearchPath_ptr;
pk_api.pkRealloc_ptr = api->pkRealloc_ptr;
pk_api.pkReleaseHandle_ptr = api->pkReleaseHandle_ptr;
pk_api.pkNewModule_ptr = api->pkNewModule_ptr;
pk_api.pkRegisterModule_ptr = api->pkRegisterModule_ptr;
pk_api.pkModuleAddFunction_ptr = api->pkModuleAddFunction_ptr;
pk_api.pkNewClass_ptr = api->pkNewClass_ptr;
pk_api.pkClassAddMethod_ptr = api->pkClassAddMethod_ptr;
pk_api.pkModuleAddSource_ptr = api->pkModuleAddSource_ptr;
pk_api.pkRunString_ptr = api->pkRunString_ptr;
pk_api.pkRunFile_ptr = api->pkRunFile_ptr;
pk_api.pkRunREPL_ptr = api->pkRunREPL_ptr;
pk_api.pkSetRuntimeError_ptr = api->pkSetRuntimeError_ptr;
pk_api.pkGetSelf_ptr = api->pkGetSelf_ptr;
pk_api.pkGetArgc_ptr = api->pkGetArgc_ptr;
pk_api.pkCheckArgcRange_ptr = api->pkCheckArgcRange_ptr;
pk_api.pkValidateSlotBool_ptr = api->pkValidateSlotBool_ptr;
pk_api.pkValidateSlotNumber_ptr = api->pkValidateSlotNumber_ptr;
pk_api.pkValidateSlotInteger_ptr = api->pkValidateSlotInteger_ptr;
pk_api.pkValidateSlotString_ptr = api->pkValidateSlotString_ptr;
pk_api.pkValidateSlotType_ptr = api->pkValidateSlotType_ptr;
pk_api.pkValidateSlotInstanceOf_ptr = api->pkValidateSlotInstanceOf_ptr;
pk_api.pkIsSlotInstanceOf_ptr = api->pkIsSlotInstanceOf_ptr;
pk_api.pkReserveSlots_ptr = api->pkReserveSlots_ptr;
pk_api.pkGetSlotsCount_ptr = api->pkGetSlotsCount_ptr;
pk_api.pkGetSlotType_ptr = api->pkGetSlotType_ptr;
pk_api.pkGetSlotBool_ptr = api->pkGetSlotBool_ptr;
pk_api.pkGetSlotNumber_ptr = api->pkGetSlotNumber_ptr;
pk_api.pkGetSlotString_ptr = api->pkGetSlotString_ptr;
pk_api.pkGetSlotHandle_ptr = api->pkGetSlotHandle_ptr;
pk_api.pkGetSlotNativeInstance_ptr = api->pkGetSlotNativeInstance_ptr;
pk_api.pkSetSlotNull_ptr = api->pkSetSlotNull_ptr;
pk_api.pkSetSlotBool_ptr = api->pkSetSlotBool_ptr;
pk_api.pkSetSlotNumber_ptr = api->pkSetSlotNumber_ptr;
pk_api.pkSetSlotString_ptr = api->pkSetSlotString_ptr;
pk_api.pkSetSlotStringLength_ptr = api->pkSetSlotStringLength_ptr;
pk_api.pkSetSlotHandle_ptr = api->pkSetSlotHandle_ptr;
pk_api.pkPlaceSelf_ptr = api->pkPlaceSelf_ptr;
pk_api.pkGetClass_ptr = api->pkGetClass_ptr;
pk_api.pkNewInstance_ptr = api->pkNewInstance_ptr;
pk_api.pkNewRange_ptr = api->pkNewRange_ptr;
pk_api.pkNewList_ptr = api->pkNewList_ptr;
pk_api.pkNewMap_ptr = api->pkNewMap_ptr;
pk_api.pkListInsert_ptr = api->pkListInsert_ptr;
pk_api.pkListPop_ptr = api->pkListPop_ptr;
pk_api.pkListLength_ptr = api->pkListLength_ptr;
pk_api.pkCallFunction_ptr = api->pkCallFunction_ptr;
pk_api.pkCallMethod_ptr = api->pkCallMethod_ptr;
pk_api.pkGetAttribute_ptr = api->pkGetAttribute_ptr;
pk_api.pkSetAttribute_ptr = api->pkSetAttribute_ptr;
pk_api.pkImportModule_ptr = api->pkImportModule_ptr;
}
PkConfiguration pkNewConfiguration() {
return pk_api.pkNewConfiguration_ptr();
}
PKVM* pkNewVM(PkConfiguration* config) {
return pk_api.pkNewVM_ptr(config);
}
void pkFreeVM(PKVM* vm) {
pk_api.pkFreeVM_ptr(vm);
}
void pkSetUserData(PKVM* vm, void* user_data) {
pk_api.pkSetUserData_ptr(vm, user_data);
}
void* pkGetUserData(const PKVM* vm) {
return pk_api.pkGetUserData_ptr(vm);
}
void pkRegisterBuiltinFn(PKVM* vm, const char* name, pkNativeFn fn, int arity, const char* docstring) {
pk_api.pkRegisterBuiltinFn_ptr(vm, name, fn, arity, docstring);
}
void pkAddSearchPath(PKVM* vm, const char* path) {
pk_api.pkAddSearchPath_ptr(vm, path);
}
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
return pk_api.pkRealloc_ptr(vm, ptr, size);
}
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
pk_api.pkReleaseHandle_ptr(vm, handle);
}
PkHandle* pkNewModule(PKVM* vm, const char* name) {
return pk_api.pkNewModule_ptr(vm, name);
}
void pkRegisterModule(PKVM* vm, PkHandle* module) {
pk_api.pkRegisterModule_ptr(vm, module);
}
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, pkNativeFn fptr, int arity) {
pk_api.pkModuleAddFunction_ptr(vm, module, name, fptr, arity);
}
PkHandle* pkNewClass(PKVM* vm, const char* name, PkHandle* base_class, PkHandle* module, pkNewInstanceFn new_fn, pkDeleteInstanceFn delete_fn) {
return pk_api.pkNewClass_ptr(vm, name, base_class, module, new_fn, delete_fn);
}
void pkClassAddMethod(PKVM* vm, PkHandle* cls, const char* name, pkNativeFn fptr, int arity) {
pk_api.pkClassAddMethod_ptr(vm, cls, name, fptr, arity);
}
void pkModuleAddSource(PKVM* vm, PkHandle* module, const char* source) {
pk_api.pkModuleAddSource_ptr(vm, module, source);
}
PkResult pkRunString(PKVM* vm, const char* source) {
return pk_api.pkRunString_ptr(vm, source);
}
PkResult pkRunFile(PKVM* vm, const char* path) {
return pk_api.pkRunFile_ptr(vm, path);
}
PkResult pkRunREPL(PKVM* vm) {
return pk_api.pkRunREPL_ptr(vm);
}
void pkSetRuntimeError(PKVM* vm, const char* message) {
pk_api.pkSetRuntimeError_ptr(vm, message);
}
void* pkGetSelf(const PKVM* vm) {
return pk_api.pkGetSelf_ptr(vm);
}
int pkGetArgc(const PKVM* vm) {
return pk_api.pkGetArgc_ptr(vm);
}
bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
return pk_api.pkCheckArgcRange_ptr(vm, argc, min, max);
}
bool pkValidateSlotBool(PKVM* vm, int slot, bool* value) {
return pk_api.pkValidateSlotBool_ptr(vm, slot, value);
}
bool pkValidateSlotNumber(PKVM* vm, int slot, double* value) {
return pk_api.pkValidateSlotNumber_ptr(vm, slot, value);
}
bool pkValidateSlotInteger(PKVM* vm, int slot, int32_t* value) {
return pk_api.pkValidateSlotInteger_ptr(vm, slot, value);
}
bool pkValidateSlotString(PKVM* vm, int slot, const char** value, uint32_t* length) {
return pk_api.pkValidateSlotString_ptr(vm, slot, value, length);
}
bool pkValidateSlotType(PKVM* vm, int slot, PkVarType type) {
return pk_api.pkValidateSlotType_ptr(vm, slot, type);
}
bool pkValidateSlotInstanceOf(PKVM* vm, int slot, int cls) {
return pk_api.pkValidateSlotInstanceOf_ptr(vm, slot, cls);
}
bool pkIsSlotInstanceOf(PKVM* vm, int inst, int cls, bool* val) {
return pk_api.pkIsSlotInstanceOf_ptr(vm, inst, cls, val);
}
void pkReserveSlots(PKVM* vm, int count) {
pk_api.pkReserveSlots_ptr(vm, count);
}
int pkGetSlotsCount(PKVM* vm) {
return pk_api.pkGetSlotsCount_ptr(vm);
}
PkVarType pkGetSlotType(PKVM* vm, int index) {
return pk_api.pkGetSlotType_ptr(vm, index);
}
bool pkGetSlotBool(PKVM* vm, int index) {
return pk_api.pkGetSlotBool_ptr(vm, index);
}
double pkGetSlotNumber(PKVM* vm, int index) {
return pk_api.pkGetSlotNumber_ptr(vm, index);
}
const char* pkGetSlotString(PKVM* vm, int index, uint32_t* length) {
return pk_api.pkGetSlotString_ptr(vm, index, length);
}
PkHandle* pkGetSlotHandle(PKVM* vm, int index) {
return pk_api.pkGetSlotHandle_ptr(vm, index);
}
void* pkGetSlotNativeInstance(PKVM* vm, int index) {
return pk_api.pkGetSlotNativeInstance_ptr(vm, index);
}
void pkSetSlotNull(PKVM* vm, int index) {
pk_api.pkSetSlotNull_ptr(vm, index);
}
void pkSetSlotBool(PKVM* vm, int index, bool value) {
pk_api.pkSetSlotBool_ptr(vm, index, value);
}
void pkSetSlotNumber(PKVM* vm, int index, double value) {
pk_api.pkSetSlotNumber_ptr(vm, index, value);
}
void pkSetSlotString(PKVM* vm, int index, const char* value) {
pk_api.pkSetSlotString_ptr(vm, index, value);
}
void pkSetSlotStringLength(PKVM* vm, int index, const char* value, uint32_t length) {
pk_api.pkSetSlotStringLength_ptr(vm, index, value, length);
}
void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle) {
pk_api.pkSetSlotHandle_ptr(vm, index, handle);
}
void pkPlaceSelf(PKVM* vm, int index) {
pk_api.pkPlaceSelf_ptr(vm, index);
}
void pkGetClass(PKVM* vm, int instance, int index) {
pk_api.pkGetClass_ptr(vm, instance, index);
}
bool pkNewInstance(PKVM* vm, int cls, int index, int argc, int argv) {
return pk_api.pkNewInstance_ptr(vm, cls, index, argc, argv);
}
void pkNewRange(PKVM* vm, int index, double first, double last) {
pk_api.pkNewRange_ptr(vm, index, first, last);
}
void pkNewList(PKVM* vm, int index) {
pk_api.pkNewList_ptr(vm, index);
}
void pkNewMap(PKVM* vm, int index) {
pk_api.pkNewMap_ptr(vm, index);
}
bool pkListInsert(PKVM* vm, int list, int32_t index, int value) {
return pk_api.pkListInsert_ptr(vm, list, index, value);
}
bool pkListPop(PKVM* vm, int list, int32_t index, int popped) {
return pk_api.pkListPop_ptr(vm, list, index, popped);
}
uint32_t pkListLength(PKVM* vm, int list) {
return pk_api.pkListLength_ptr(vm, list);
}
bool pkCallFunction(PKVM* vm, int fn, int argc, int argv, int ret) {
return pk_api.pkCallFunction_ptr(vm, fn, argc, argv, ret);
}
bool pkCallMethod(PKVM* vm, int instance, const char* method, int argc, int argv, int ret) {
return pk_api.pkCallMethod_ptr(vm, instance, method, argc, argv, ret);
}
bool pkGetAttribute(PKVM* vm, int instance, const char* name, int index) {
return pk_api.pkGetAttribute_ptr(vm, instance, name, index);
}
bool pkSetAttribute(PKVM* vm, int instance, const char* name, int value) {
return pk_api.pkSetAttribute_ptr(vm, instance, name, value);
}
bool pkImportModule(PKVM* vm, const char* path, int index) {
return pk_api.pkImportModule_ptr(vm, path, index);
}

View File

@ -13,12 +13,8 @@ int main(int argc, char** argv) {
// Run a string.
pkRunString(vm, "print('hello world')");
// TODO: move path module to src/ or write a simple path resolving
// function to support pkRunFile() without requesting someone
// to provide path resolving function.
//
// Run a script from file.
//pkRunFile(vm, "script.pk");
// Run from file.
pkRunFile(vm, "script.pk");
// Free the VM.
pkFreeVM(vm);

2
tests/native/script.pk Normal file
View File

@ -0,0 +1,2 @@
print('hello from pocket script')