mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
Merge pull request #246 from ThakeeNathees/extension-module
Extension module implemented
This commit is contained in:
commit
52b2d1d8cb
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ CC = gcc
|
|||||||
CFLAGS = -fPIC
|
CFLAGS = -fPIC
|
||||||
DEBUG_CFLAGS = -D DEBUG -g3 -Og
|
DEBUG_CFLAGS = -D DEBUG -g3 -Og
|
||||||
RELEASE_CFLAGS = -g -O3
|
RELEASE_CFLAGS = -g -O3
|
||||||
LDFLAGS = -lm
|
LDFLAGS = -lm -ldl
|
||||||
|
|
||||||
TARGET_EXEC = pocket
|
TARGET_EXEC = pocket
|
||||||
BUILD_DIR = ./build/
|
BUILD_DIR = ./build/
|
||||||
|
12
README.md
12
README.md
@ -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 / 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
|
#### MSVC
|
||||||
@ -93,10 +93,12 @@ for the MSVS installation path and setup the build environment.
|
|||||||
### For other compiler/IDE
|
### For other compiler/IDE
|
||||||
|
|
||||||
1. Create an empty project file / makefile.
|
1. Create an empty project file / makefile.
|
||||||
2. Add all C files in the src directory.
|
2. Add all C files in the src/core/ directory.
|
||||||
3. Add all C files in the cli directory (**NOT** recursively).
|
3. Add all C files in the src/libs/ directory.
|
||||||
4. Add `src/include` to include path.
|
4. Add all C files in the cli/ directory.
|
||||||
5. Compile.
|
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
|
Visual studio project files can be generated with the premake, see
|
||||||
[scripts/README](https://github.com/ThakeeNathees/pocketlang/scripts/README.md)
|
[scripts/README](https://github.com/ThakeeNathees/pocketlang/scripts/README.md)
|
||||||
|
@ -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()
|
|
@ -11,12 +11,12 @@ from os.path import (join, exists, abspath,
|
|||||||
## the root path.
|
## the root path.
|
||||||
ROOT_PATH = abspath(join(dirname(__file__), "../"))
|
ROOT_PATH = abspath(join(dirname(__file__), "../"))
|
||||||
|
|
||||||
NATIVE_HEADER = "pknative.gen.h"
|
NATIVE_API_EXT = "pknative.c"
|
||||||
NATIVE_SOURCE = "nativeapi.gen.h"
|
NATIVE_API_IMP = "nativeapi.h"
|
||||||
|
|
||||||
POCKET_HEADER = join(ROOT_PATH, f"src/include/pocketlang.h")
|
POCKET_HEADER = join(ROOT_PATH, f"src/include/pocketlang.h")
|
||||||
TARGET_HEADER = join(ROOT_PATH, f"src/include/{NATIVE_HEADER}")
|
TARGET_EXT = join(ROOT_PATH, f"tests/native/dl/{NATIVE_API_EXT}")
|
||||||
TARGET_SOURCE = join(ROOT_PATH, f"src/core/{NATIVE_SOURCE}")
|
TARGET_IMP = join(ROOT_PATH, f"src/libs/gen/{NATIVE_API_IMP}")
|
||||||
DL_IMPLEMENT = 'PK_DL_IMPLEMENT'
|
DL_IMPLEMENT = 'PK_DL_IMPLEMENT'
|
||||||
|
|
||||||
PK_API = "pk_api"
|
PK_API = "pk_api"
|
||||||
@ -38,11 +38,7 @@ HEADER = f'''\
|
|||||||
* Copyright (c) 2021-2022 Pocketlang Contributors
|
* Copyright (c) 2021-2022 Pocketlang Contributors
|
||||||
* Distributed Under The MIT License
|
* Distributed Under The MIT License
|
||||||
*/
|
*/
|
||||||
|
%s
|
||||||
#ifndef PK_AMALGAMATED
|
|
||||||
#include <pocketlang.h>%s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// !! THIS FILE IS GENERATED DO NOT EDIT !!
|
// !! THIS FILE IS GENERATED DO NOT EDIT !!
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -135,18 +131,16 @@ def generate():
|
|||||||
api_functions = get_api_functions()
|
api_functions = get_api_functions()
|
||||||
|
|
||||||
## Generate pocket native header.
|
## Generate pocket native header.
|
||||||
with open(TARGET_HEADER, 'w') as fp:
|
with open(TARGET_EXT, 'w') as fp:
|
||||||
fp.write(HEADER % '')
|
fp.write(HEADER % '\n#include <pocketlang.h>\n')
|
||||||
fp.write(fn_typedefs(api_functions))
|
fp.write(fn_typedefs(api_functions))
|
||||||
fp.write(api_typedef(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(init_api(api_functions))
|
||||||
fp.write(define_functions(api_functions))
|
fp.write(define_functions(api_functions))
|
||||||
fp.write(f'\n#endif //{DL_IMPLEMENT}\n')
|
|
||||||
|
|
||||||
## Generate native api source.
|
## Generate native api source.
|
||||||
with open(TARGET_SOURCE, 'w') as fp:
|
with open(TARGET_IMP, 'w') as fp:
|
||||||
fp.write(HEADER % '')
|
fp.write(HEADER % '\n#ifndef PK_AMALGAMATED\n#include <pocketlang.h>\n#endif\n\n')
|
||||||
|
|
||||||
fp.write(fn_typedefs(api_functions))
|
fp.write(fn_typedefs(api_functions))
|
||||||
fp.write(api_typedef(api_functions))
|
fp.write(api_typedef(api_functions))
|
||||||
@ -163,5 +157,5 @@ def generate():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
generate()
|
generate()
|
||||||
print("Generated:", relpath(TARGET_HEADER, ROOT_PATH))
|
print("Generated:", relpath(TARGET_EXT, ROOT_PATH))
|
||||||
print("Generated:", relpath(TARGET_SOURCE, ROOT_PATH))
|
print("Generated:", relpath(TARGET_IMP, ROOT_PATH))
|
||||||
|
@ -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()
|
|
@ -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
|
||||||
|
@ -51,10 +51,6 @@
|
|||||||
// Dump the stack values and the globals.
|
// Dump the stack values and the globals.
|
||||||
#define DUMP_STACK 0
|
#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"
|
// Nan-Tagging could be disable for debugging/portability purposes. See "var.h"
|
||||||
// header for more information on Nan-tagging.
|
// header for more information on Nan-tagging.
|
||||||
#define VAR_NAN_TAGGING 1
|
#define VAR_NAN_TAGGING 1
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#endif
|
#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
|
// Pocketlang core doesn't implement path resolving funcionality. Rather it
|
||||||
// should be provided the host application. By default we're using an
|
// should be provided the host application. By default we're using an
|
||||||
@ -32,6 +32,13 @@
|
|||||||
void registerLibs(PKVM* vm);
|
void registerLibs(PKVM* vm);
|
||||||
void cleanupLibs(PKVM* vm);
|
void cleanupLibs(PKVM* vm);
|
||||||
char* pathResolveImport(PKVM* vm, const char* from, const char* path);
|
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
|
#endif
|
||||||
|
|
||||||
#define CHECK_ARG_NULL(name) \
|
#define CHECK_ARG_NULL(name) \
|
||||||
@ -81,15 +88,8 @@ static char* stdinRead(PKVM* vm);
|
|||||||
static char* loadScript(PKVM* vm, const char* path);
|
static char* loadScript(PKVM* vm, const char* path);
|
||||||
|
|
||||||
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
|
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
|
||||||
|
|
||||||
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
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);
|
return vm->config.realloc_fn(ptr, size, vm->config.user_data);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PkConfiguration pkNewConfiguration() {
|
PkConfiguration pkNewConfiguration() {
|
||||||
@ -103,6 +103,13 @@ PkConfiguration pkNewConfiguration() {
|
|||||||
config.stdin_read = stdinRead;
|
config.stdin_read = stdinRead;
|
||||||
#ifndef PK_NO_LIBS
|
#ifndef PK_NO_LIBS
|
||||||
config.resolve_path_fn = pathResolveImport;
|
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
|
#endif
|
||||||
config.load_script_fn = loadScript;
|
config.load_script_fn = loadScript;
|
||||||
|
|
||||||
|
@ -1143,6 +1143,9 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
pkVarBufferClear(&module->globals, vm);
|
pkVarBufferClear(&module->globals, vm);
|
||||||
pkUintBufferClear(&module->global_names, vm);
|
pkUintBufferClear(&module->global_names, vm);
|
||||||
pkVarBufferClear(&module->constants, vm);
|
pkVarBufferClear(&module->constants, vm);
|
||||||
|
#ifndef PK_NO_DL
|
||||||
|
if (module->handle) vmUnloadDlHandle(vm, module->handle);
|
||||||
|
#endif
|
||||||
DEALLOCATE(vm, self, Module);
|
DEALLOCATE(vm, self, Module);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -311,6 +311,13 @@ struct Module {
|
|||||||
// will be set to true. If a module doesn't have globals, We can safely set
|
// 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.
|
// it to true to prevent from running the above body function, if it has one.
|
||||||
bool initialized;
|
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.
|
// A struct contain opcodes and other information of a compiled function.
|
||||||
|
107
src/core/vm.c
107
src/core/vm.c
@ -47,39 +47,7 @@ void* vmRealloc(PKVM* vm, void* memory, size_t old_size, size_t new_size) {
|
|||||||
vm->collecting_garbage = false;
|
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);
|
return vm->config.realloc_fn(memory, new_size, vm->config.user_data);
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vmPushTempRef(PKVM* vm, Object* obj) {
|
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);
|
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 */
|
/* 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
|
// The script not exists in the VM, make sure we have the script loading
|
||||||
// api function.
|
// 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) {
|
if (vm->config.load_script_fn == NULL) {
|
||||||
|
#endif
|
||||||
|
|
||||||
VM_SET_ERROR(vm, newString(vm, "Cannot import. The hosting application "
|
VM_SET_ERROR(vm, newString(vm, "Cannot import. The hosting application "
|
||||||
"haven't registered the module loading API"));
|
"haven't registered the module loading API"));
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
@ -485,7 +522,13 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
|
|||||||
}
|
}
|
||||||
_name->hash = utilHashString(_name->data);
|
_name->hash = utilHashString(_name->data);
|
||||||
vmPushTempRef(vm, &_name->_super); // _name.
|
vmPushTempRef(vm, &_name->_super); // _name.
|
||||||
|
|
||||||
|
#ifndef PK_NO_DL
|
||||||
|
if (isdl) module = _importDL(vm, resolved, _name);
|
||||||
|
else /* ... */
|
||||||
|
#endif
|
||||||
module = _importScript(vm, resolved, _name);
|
module = _importScript(vm, resolved, _name);
|
||||||
|
|
||||||
vmPopTempRef(vm); // _name.
|
vmPopTempRef(vm); // _name.
|
||||||
}
|
}
|
||||||
vmPopTempRef(vm); // resolved.
|
vmPopTempRef(vm); // resolved.
|
||||||
|
@ -248,4 +248,11 @@ PkResult vmCallMethod(PKVM* vm, Var self, Closure* fn,
|
|||||||
// On failure, it'll set an error and return VAR_NULL.
|
// On failure, it'll set an error and return VAR_NULL.
|
||||||
Var vmImportModule(PKVM* vm, String* from, String* path);
|
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
|
#endif // PK_VM_H
|
||||||
|
@ -109,6 +109,24 @@ typedef void (*pkSignalFn) (void*);
|
|||||||
// the VM will claim the ownership of the string.
|
// the VM will claim the ownership of the string.
|
||||||
typedef char* (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
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
|
// 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
|
// 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
|
// 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;
|
pkResolvePathFn resolve_path_fn;
|
||||||
pkLoadScriptFn load_script_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.
|
// If true stderr calls will use ansi color codes.
|
||||||
bool use_ansi_escape;
|
bool use_ansi_escape;
|
||||||
|
|
||||||
|
205
src/libs/gen/nativeapi.h
Normal file
205
src/libs/gen/nativeapi.h
Normal 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
|
@ -51,6 +51,19 @@ void cleanupLibs(PKVM* vm);
|
|||||||
// inorder to use the import statements.
|
// inorder to use the import statements.
|
||||||
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
|
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
|
// Write the executable's path to the buffer and return true, if it failed
|
||||||
// it'll return false.
|
// it'll return false.
|
||||||
bool osGetExeFilePath(char* buff, int size);
|
bool osGetExeFilePath(char* buff, int size);
|
||||||
|
@ -29,21 +29,20 @@
|
|||||||
#define _PKOS_LINUX_
|
#define _PKOS_LINUX_
|
||||||
#define OS_NAME "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
|
#else
|
||||||
#define _PKOS_UNKNOWN_
|
#define _PKOS_UNKNOWN_
|
||||||
#define OS_NAME "<?>"
|
#define OS_NAME "<?>"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
|
#if defined(_PKOS_WIN_)
|
||||||
#include <windows.h>
|
#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 <direct.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
|
||||||
@ -65,6 +64,88 @@
|
|||||||
// See: https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
// See: https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
||||||
#define MAX_PATH_LEN 4096
|
#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) {
|
bool osGetExeFilePath(char* buff, int size) {
|
||||||
|
|
||||||
#if defined(_PKOS_WIN_)
|
#if defined(_PKOS_WIN_)
|
||||||
|
@ -97,6 +97,13 @@ static char* tryImportPaths(PKVM* vm, char* path, char* buff) {
|
|||||||
"",
|
"",
|
||||||
".pk",
|
".pk",
|
||||||
"/_init.pk",
|
"/_init.pk",
|
||||||
|
#ifndef PK_NO_DL
|
||||||
|
#ifdef _WIN32
|
||||||
|
".dll",
|
||||||
|
#else
|
||||||
|
".so",
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
NULL, // Sentinal to mark the array end.
|
NULL, // Sentinal to mark the array end.
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -382,16 +389,11 @@ void _registerSearchPaths(PKVM* vm) {
|
|||||||
buff[length++] = last;
|
buff[length++] = last;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff[length] = '\0';
|
|
||||||
|
|
||||||
pkAddSearchPath(vm, buff);
|
|
||||||
|
|
||||||
// FIXME: the bellow code is hard coded.
|
// FIXME: the bellow code is hard coded.
|
||||||
if (length + strlen("libs/") < MAX_PATH_LEN) {
|
ASSERT(length + strlen("libs/") < MAX_PATH_LEN, OOPS);
|
||||||
strcpy(buff + length, (ps == CWK_STYLE_WINDOWS) ? "libs\\" : "libs/");
|
strcpy(buff + length, (ps == CWK_STYLE_WINDOWS) ? "libs\\" : "libs/");
|
||||||
pkAddSearchPath(vm, buff);
|
pkAddSearchPath(vm, buff);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void registerModulePath(PKVM* vm) {
|
void registerModulePath(PKVM* vm) {
|
||||||
|
|
||||||
|
14
tests/native/dl/README.md
Normal file
14
tests/native/dl/README.md
Normal 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
9
tests/native/dl/main.pk
Normal 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
14
tests/native/dl/mylib.c
Normal 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
417
tests/native/dl/pknative.c
Normal 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);
|
||||||
|
}
|
@ -13,12 +13,8 @@ int main(int argc, char** argv) {
|
|||||||
// Run a string.
|
// Run a string.
|
||||||
pkRunString(vm, "print('hello world')");
|
pkRunString(vm, "print('hello world')");
|
||||||
|
|
||||||
// TODO: move path module to src/ or write a simple path resolving
|
// Run from file.
|
||||||
// function to support pkRunFile() without requesting someone
|
pkRunFile(vm, "script.pk");
|
||||||
// to provide path resolving function.
|
|
||||||
//
|
|
||||||
// Run a script from file.
|
|
||||||
//pkRunFile(vm, "script.pk");
|
|
||||||
|
|
||||||
// Free the VM.
|
// Free the VM.
|
||||||
pkFreeVM(vm);
|
pkFreeVM(vm);
|
||||||
|
2
tests/native/script.pk
Normal file
2
tests/native/script.pk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
print('hello from pocket script')
|
Loading…
Reference in New Issue
Block a user