mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-01-28 08:20:27 +08:00
extension module implemented
now it's possible to import a dynamic libray (*.dll, *.so) in a pocket script.
This commit is contained in:
parent
3136eb4817
commit
bd61e77593
2
Makefile
2
Makefile
@ -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/
|
||||
|
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 -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)
|
||||
|
@ -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.
|
||||
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))
|
||||
|
@ -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.
|
||||
#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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
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;
|
||||
}
|
||||
|
||||
#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.
|
||||
|
@ -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
|
||||
|
@ -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
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.
|
||||
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);
|
||||
|
@ -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_)
|
||||
|
@ -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
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.
|
||||
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
2
tests/native/script.pk
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
print('hello from pocket script')
|
Loading…
Reference in New Issue
Block a user