mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
Native function api implemented
This commit is contained in:
parent
82982d3ceb
commit
8738ccfe64
43
cli/cli_modules.c
Normal file
43
cli/cli_modules.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Thakee Nathees
|
||||
* Licensed under: MIT License
|
||||
*/
|
||||
|
||||
#include "pocketlang.h"
|
||||
|
||||
// FIXME: everything below here is temproary and for testing.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void stdPathAbspath(PKVM* vm) {
|
||||
PkVar path;
|
||||
if (!pkGetArgValue(vm, 1, PK_STRING, &path)) return;
|
||||
|
||||
const char* data = pkStringGetData(path);
|
||||
|
||||
pkReturnNull(vm);
|
||||
}
|
||||
|
||||
void stdPathCurdir(PKVM* vm) {
|
||||
pkReturnNull(vm);
|
||||
}
|
||||
|
||||
void testAdd(PKVM* vm) {
|
||||
double v1, v2;
|
||||
if (!pkGetArgNumber(vm, 1, &v1)) return;
|
||||
if (!pkGetArgNumber(vm, 2, &v2)) return;
|
||||
|
||||
double total = v1 + v2;
|
||||
|
||||
pkReturnNumber(vm, total);
|
||||
}
|
||||
|
||||
void register_cli_modules(PKVM* vm) {
|
||||
PkHandle* path = pkNewModule(vm, "path");
|
||||
pkModuleAddFunction(vm, path, "abspath", stdPathAbspath, 1);
|
||||
pkModuleAddFunction(vm, path, "curdir", stdPathCurdir, 0);
|
||||
|
||||
PkHandle* test = pkNewModule(vm, "test");
|
||||
pkModuleAddFunction(vm, test, "add", testAdd, 2);
|
||||
|
||||
}
|
25
cli/main.c
25
cli/main.c
@ -9,7 +9,15 @@
|
||||
|
||||
#include "pocketlang.h"
|
||||
|
||||
void errorPrint(PKVM* vm, PKErrorType type, const char* file, int line,
|
||||
// FIXME: everything below here is temproary and for testing.
|
||||
|
||||
// TODO: include this.
|
||||
void register_cli_modules(PKVM* vm);
|
||||
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
void errorPrint(PKVM* vm, PkErrorType type, const char* file, int line,
|
||||
const char* message) {
|
||||
if (type == PK_ERROR_COMPILE) {
|
||||
fprintf(stderr, "Error: %s\n at %s:%i\n", message, file, line);
|
||||
@ -101,16 +109,15 @@ int main(int argc, char** argv) {
|
||||
// FIXME: this is temp till arg parse implemented.
|
||||
if (argc >= 3 && strcmp(argv[1], "-c") == 0) {
|
||||
PKVM* vm = pkNewVM(&config);
|
||||
PKInterpretResult result = pkInterpretSource(vm, argv[2], "$(Source)");
|
||||
pkFreeVM(vm);
|
||||
return result;
|
||||
|
||||
} else {
|
||||
PKVM* vm = pkNewVM(&config);
|
||||
PKInterpretResult result = pkInterpret(vm, argv[1]);
|
||||
PkInterpretResult result = pkInterpretSource(vm, argv[2], "$(Source)");
|
||||
pkFreeVM(vm);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
PKVM* vm = pkNewVM(&config);
|
||||
register_cli_modules(vm);
|
||||
|
||||
PkInterpretResult result = pkInterpret(vm, argv[1]);
|
||||
pkFreeVM(vm);
|
||||
return result;
|
||||
}
|
||||
|
21
src/common.h
21
src/common.h
@ -23,7 +23,11 @@
|
||||
|
||||
#include <stdio.h> //< Only needed for ASSERT() macro and for release mode
|
||||
//< TODO; macro use this to print a crash report.
|
||||
// The internal assertion macro, do not use this. Use ASSERT() instead.
|
||||
|
||||
// The internal assertion macro, this will print error and break regardless of
|
||||
// the build target (debug or release). Use ASSERT() for debug assertion and
|
||||
// use __ASSERT() for TODOs and assetion's in public methods (to indicate that
|
||||
// the host application did something wrong).
|
||||
#define __ASSERT(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
@ -103,19 +107,22 @@
|
||||
#define DEALLOCATE(vm, pointer) \
|
||||
vmRealloc(vm, pointer, 0, 0)
|
||||
|
||||
// Unique number to identify for various cases.
|
||||
typedef uint32_t ID;
|
||||
|
||||
#if VAR_NAN_TAGGING
|
||||
typedef uint64_t Var;
|
||||
#else
|
||||
typedef struct Var Var;
|
||||
#endif
|
||||
|
||||
typedef struct Object Object;
|
||||
typedef struct String String;
|
||||
typedef struct List List;
|
||||
typedef struct Map Map;
|
||||
typedef struct Range Range;
|
||||
|
||||
typedef struct Script Script;
|
||||
typedef struct Function Function;
|
||||
|
||||
// Unique number to identify for various cases.
|
||||
typedef uint32_t ID;
|
||||
|
||||
// VM's fiber type.
|
||||
typedef struct Fiber Fiber;
|
||||
|
||||
#endif //PK_COMMON_H
|
||||
|
239
src/core.c
239
src/core.c
@ -13,6 +13,137 @@
|
||||
#include "var.h"
|
||||
#include "vm.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Declare internal functions of public api.
|
||||
static Script* newModuleInternal(PKVM* vm, const char* name);
|
||||
static void moduleAddFunctionInternal(PKVM* vm, Script* script,
|
||||
const char* name, pkNativeFn fptr, int arity);
|
||||
|
||||
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||
Script* module = newModuleInternal(vm, name);
|
||||
return vmNewHandle(vm, VAR_OBJ(&module->_super));
|
||||
}
|
||||
|
||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
||||
pkNativeFn fptr, int arity) {
|
||||
__ASSERT(module != NULL, "Argument module was NULL.");
|
||||
|
||||
Var scr = module->value;
|
||||
__ASSERT(IS_OBJ(scr) && AS_OBJ(scr)->type == OBJ_SCRIPT,
|
||||
"Given handle is not a module");
|
||||
|
||||
moduleAddFunctionInternal(vm, (Script*)AS_OBJ(scr), name, fptr, arity);
|
||||
}
|
||||
|
||||
// Argument getter (1 based).
|
||||
#define ARG(n) vm->fiber->ret[n]
|
||||
|
||||
// Convinent macros.
|
||||
#define ARG1 ARG(1)
|
||||
#define ARG2 ARG(2)
|
||||
#define ARG3 ARG(3)
|
||||
|
||||
// Argument count used in variadic functions.
|
||||
#define ARGC ((int)(vm->fiber->sp - vm->fiber->ret) - 1)
|
||||
|
||||
// Set return value.
|
||||
#define RET(value) \
|
||||
do { \
|
||||
*(vm->fiber->ret) = value; \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
// Check for errors in before calling the get arg public api function.
|
||||
#define CHECK_GET_ARG_API_ERRORS() \
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); \
|
||||
__ASSERT(arg > 0 || arg < ARGC, "Invalid argument index."); \
|
||||
__ASSERT(value != NULL, "Parameter [value] was NULL."); \
|
||||
((void*)0)
|
||||
|
||||
#define ERR_INVALID_ARG_TYPE(m_type) \
|
||||
do { \
|
||||
/* 12 chars is enought for a 4 byte integer string.*/ \
|
||||
char buff[12]; \
|
||||
sprintf(buff, "%d", arg); \
|
||||
vm->fiber->error = stringFormat(vm, "Expected a " m_type \
|
||||
" at argument $.", buff); \
|
||||
} while (false)
|
||||
|
||||
int pkGetArgc(PKVM* vm) {
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
return ARGC;
|
||||
}
|
||||
|
||||
PkVar pkGetArg(PKVM* vm, int arg) {
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
__ASSERT(arg > 0 || arg < ARGC, "Invalid argument index.");
|
||||
|
||||
return &(ARG(arg));
|
||||
}
|
||||
|
||||
bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
|
||||
CHECK_GET_ARG_API_ERRORS();
|
||||
|
||||
Var val = ARG(arg);
|
||||
if (IS_NUM(val)) {
|
||||
*value = AS_NUM(val);
|
||||
|
||||
} else if (IS_BOOL(val)) {
|
||||
*value = AS_BOOL(val) ? 1 : 0;
|
||||
|
||||
} else {
|
||||
ERR_INVALID_ARG_TYPE("number");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
|
||||
CHECK_GET_ARG_API_ERRORS();
|
||||
|
||||
Var val = ARG(arg);
|
||||
*value = toBool(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
|
||||
CHECK_GET_ARG_API_ERRORS();
|
||||
|
||||
Var val = ARG(arg);
|
||||
if (pkGetValueType((PkVar)&val) != type) {
|
||||
char buff[12]; sprintf(buff, "%d", arg);
|
||||
vm->fiber->error = stringFormat(vm,
|
||||
"Expected a $ at argument $.", getPkVarTypeName(type), buff);
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = (PkVar)&val;
|
||||
return true;
|
||||
}
|
||||
|
||||
void pkReturnNull(PKVM* vm) {
|
||||
RET(VAR_NULL);
|
||||
}
|
||||
|
||||
void pkReturnBool(PKVM* vm, bool value) {
|
||||
RET(VAR_BOOL(value));
|
||||
}
|
||||
|
||||
void pkReturnNumber(PKVM* vm, double value) {
|
||||
RET(VAR_NUM(value));
|
||||
}
|
||||
|
||||
void pkReturnValue(PKVM* vm, PkVar value) {
|
||||
RET(*(Var*)value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Convert number var as int32_t. Check if it's number before using it.
|
||||
#define _AS_INTEGER(var) (int32_t)trunc(AS_NUM(var))
|
||||
|
||||
@ -104,23 +235,6 @@ static bool validateArgString(PKVM* vm, Var var, String** value, int arg_ind) {
|
||||
/* BUILTIN FUNCTIONS API */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Argument getter (1 based).
|
||||
#define ARG(n) vm->fiber->ret[n]
|
||||
|
||||
// Convinent macros.
|
||||
#define ARG1 ARG(1)
|
||||
#define ARG2 ARG(2)
|
||||
#define ARG3 ARG(3)
|
||||
|
||||
// Argument count used in variadic functions.
|
||||
#define ARGC ((int)(vm->fiber->sp - vm->fiber->ret) - 1)
|
||||
|
||||
// Set return value.
|
||||
#define RET(value) \
|
||||
do { \
|
||||
*(vm->fiber->ret) = value; \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
Function* getBuiltinFunction(PKVM* vm, int index) {
|
||||
ASSERT_INDEX(index, vm->builtins_count);
|
||||
@ -276,25 +390,54 @@ void coreStrStrip(PKVM* vm) {
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CORE LIBRARY METHODS */
|
||||
/* CORE MODULE METHODS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// 'path' library methods.
|
||||
// -----------------------
|
||||
// Create a module and add it to the vm's core modules, returns the script.
|
||||
static Script* newModuleInternal(PKVM* vm, const char* name) {
|
||||
|
||||
// TODO: path library should be added by the cli (or the hosting application).
|
||||
void stdPathAbspath(PKVM* vm) {
|
||||
Var relpath = ARG1;
|
||||
if (!IS_OBJ(relpath) || AS_OBJ(relpath)->type != OBJ_STRING) {
|
||||
vm->fiber->error = newString(vm, "Expected a string at argument 1.");
|
||||
// Create a new Script for the module.
|
||||
String* _name = newString(vm, name);
|
||||
vmPushTempRef(vm, &_name->_super);
|
||||
|
||||
// Check if any module with the same name already exists and assert to the
|
||||
// hosting application.
|
||||
if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(&_name->_super)))) {
|
||||
vmPopTempRef(vm); // _name
|
||||
__ASSERT(false, stringFormat(vm, "A module named '$' already exists",
|
||||
name)->data);
|
||||
}
|
||||
|
||||
// TODO: abspath.
|
||||
RET(VAR_OBJ(newString(vm, "TODO: abspath")));
|
||||
Script* scr = newScript(vm, _name);
|
||||
scr->moudle = _name;
|
||||
vmPopTempRef(vm); // _name
|
||||
|
||||
// Add the script to core_libs.
|
||||
vmPushTempRef(vm, &scr->_super);
|
||||
mapSet(vm, vm->core_libs, VAR_OBJ(&_name->_super), VAR_OBJ(&scr->_super));
|
||||
vmPopTempRef(vm);
|
||||
|
||||
return scr;
|
||||
}
|
||||
|
||||
void stdPathCurdir(PKVM* vm) {
|
||||
RET(VAR_OBJ(newString(vm, "TODO: curdir")));
|
||||
static void moduleAddFunctionInternal(PKVM* vm, Script* script,
|
||||
const char* name, pkNativeFn fptr, int arity) {
|
||||
|
||||
// Check if function with the same name already exists.
|
||||
if (scriptSearchFunc(script, name, (uint32_t)strlen(name)) != -1) {
|
||||
__ASSERT(false, stringFormat(vm, "A function named '$' already esists "
|
||||
"on module '@'", name, script->moudle)->data);
|
||||
}
|
||||
|
||||
// Check if a global variable with the same name already exists.
|
||||
if (scriptSearchGlobals(script, name, (uint32_t)strlen(name)) != -1) {
|
||||
__ASSERT(false, stringFormat(vm, "A global variable named '$' already "
|
||||
"esists on module '@'", name, script->moudle)->data);
|
||||
}
|
||||
|
||||
Function* fn = newFunction(vm, name, (int)strlen(name), script, true);
|
||||
fn->native = fptr;
|
||||
fn->arity = arity;
|
||||
}
|
||||
|
||||
// 'lang' library methods.
|
||||
@ -367,40 +510,12 @@ void initializeCore(PKVM* vm) {
|
||||
INITALIZE_BUILTIN_FN("str_upper", coreStrUpper, 1);
|
||||
INITALIZE_BUILTIN_FN("str_strip", coreStrStrip, 1);
|
||||
|
||||
// Make STD scripts.
|
||||
Script* std; // A temporary pointer to the current std script.
|
||||
Function* fn; // A temporary pointer to the allocated function function.
|
||||
#define STD_NEW_SCRIPT(_name) \
|
||||
do { \
|
||||
/* Create a new Script. */ \
|
||||
String* name = newString(vm, _name); \
|
||||
vmPushTempRef(vm, &name->_super); \
|
||||
std = newScript(vm, name); \
|
||||
std->moudle = name; /* Core libs's path and the module are the same. */ \
|
||||
vmPopTempRef(vm); \
|
||||
/* Add the script to core_libs. */ \
|
||||
vmPushTempRef(vm, &std->_super); \
|
||||
mapSet(vm, vm->core_libs, VAR_OBJ(&name->_super), VAR_OBJ(&std->_super)); \
|
||||
vmPopTempRef(vm); \
|
||||
} while (false)
|
||||
// Core Modules /////////////////////////////////////////////////////////////
|
||||
|
||||
#define STD_ADD_FUNCTION(_name, fptr, _arity) \
|
||||
do { \
|
||||
fn = newFunction(vm, _name, (int)strlen(_name), std, true); \
|
||||
fn->native = fptr; \
|
||||
fn->arity = _arity; \
|
||||
} while (false)
|
||||
|
||||
// path
|
||||
STD_NEW_SCRIPT("path");
|
||||
STD_ADD_FUNCTION("abspath", stdPathAbspath, 1);
|
||||
STD_ADD_FUNCTION("curdir", stdPathCurdir, 0);
|
||||
|
||||
// lang
|
||||
STD_NEW_SCRIPT("lang");
|
||||
STD_ADD_FUNCTION("clock", stdLangClock, 0);
|
||||
STD_ADD_FUNCTION("gc", stdLangGC, 0);
|
||||
STD_ADD_FUNCTION("write", stdLangWrite, -1);
|
||||
Script* lang = newModuleInternal(vm, "lang");
|
||||
moduleAddFunctionInternal(vm, lang, "clock", stdLangClock, 0);
|
||||
moduleAddFunctionInternal(vm, lang, "gc", stdLangGC, 0);
|
||||
moduleAddFunctionInternal(vm, lang, "write", stdLangWrite, -1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -3,8 +3,8 @@
|
||||
* Licensed under: MIT License
|
||||
*/
|
||||
|
||||
#ifndef MINISCRIPT_H
|
||||
#define MINISCRIPT_H
|
||||
#ifndef POCKETLANG_H
|
||||
#define POCKETLANG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -14,7 +14,14 @@ extern "C" {
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG DEFINES */
|
||||
/*****************************************************************************/
|
||||
|
||||
// The version number macros.
|
||||
// Major Version - Increment when changes break compatibility.
|
||||
// Minor Version - Increment when new functionality added to public api.
|
||||
// Patch Version - Increment when bug fixed or minor changes between releases.
|
||||
#define PK_VERSION_MAJOR 0
|
||||
#define PK_VERSION_MINOR 1
|
||||
#define PK_VERSION_PATCH 0
|
||||
@ -22,8 +29,9 @@ extern "C" {
|
||||
// String representation of the value.
|
||||
#define PK_VERSION_STRING "0.1.0"
|
||||
|
||||
// miniscript visibility macros. define PK_DLL for using miniscript as a
|
||||
// shared library and define PK_COMPILE to export symbols.
|
||||
// Pocketlang visibility macros. define PK_DLL for using pocketlang as a
|
||||
// shared library and define PK_COMPILE to export symbols when compiling the
|
||||
// pocketlang it self as a shared library.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _PK_EXPORT __declspec(dllexport)
|
||||
@ -46,24 +54,72 @@ extern "C" {
|
||||
#define PK_PUBLIC
|
||||
#endif
|
||||
|
||||
// MiniScript Virtual Machine.
|
||||
// it'll contain the state of the execution, stack, heap, and manage memory
|
||||
// allocations.
|
||||
typedef struct PKVM PKVM;
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG TYPES */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Nan-Tagging could be disable for debugging/portability purposes only when
|
||||
// compiling the compiler. Do not change this if using the miniscript library
|
||||
// compiling the compiler. Do not change this if using the pocketlang library
|
||||
// for embedding. To disable when compiling the compiler, define
|
||||
// `VAR_NAN_TAGGING 0`, otherwise it defaults to Nan-Tagging.
|
||||
#ifndef VAR_NAN_TAGGING
|
||||
#define VAR_NAN_TAGGING 1
|
||||
#endif
|
||||
|
||||
#if VAR_NAN_TAGGING
|
||||
typedef uint64_t Var;
|
||||
#else
|
||||
typedef struct Var Var;
|
||||
#endif
|
||||
// PocketLang Virtual Machine. It'll contain the state of the execution, stack,
|
||||
// heap, and manage memory allocations.
|
||||
typedef struct PKVM PKVM;
|
||||
|
||||
// A handle to the pocketlang variables. It'll hold the reference to the
|
||||
// variable and ensure that the variable it holds won't be garbage collected
|
||||
// till it released with pkReleaseHandle().
|
||||
typedef struct PkHandle PkHandle;
|
||||
|
||||
// A temproary pointer to the pocketlang variable. This pointer is aquired
|
||||
// from the pocketlang's current stack frame and the pointer will become
|
||||
// dangling once after the stack frame is popped.
|
||||
typedef void* PkVar;
|
||||
|
||||
// Type enum of the pocketlang varaibles, this can be used to get the type
|
||||
// from a Var* in the method pkGetVarType().
|
||||
typedef enum {
|
||||
PK_NULL,
|
||||
PK_BOOL,
|
||||
PK_NUMBER,
|
||||
PK_STRING,
|
||||
PK_LIST,
|
||||
PK_MAP,
|
||||
PK_RANGE,
|
||||
PK_SCRIPT,
|
||||
PK_FUNCTION,
|
||||
PK_FIBER,
|
||||
} PkVarType;
|
||||
|
||||
typedef struct pkStringPtr pkStringPtr;
|
||||
typedef struct pkConfiguration pkConfiguration;
|
||||
|
||||
// Type of the error message that pocketlang will provide with the pkErrorFn
|
||||
// callback.
|
||||
typedef enum {
|
||||
PK_ERROR_COMPILE = 0, // Compile time errors.
|
||||
PK_ERROR_RUNTIME, // Runtime error message.
|
||||
PK_ERROR_STACKTRACE, // One entry of a runtime error stack.
|
||||
} PkErrorType;
|
||||
|
||||
// Result that pocketlang will return after running a script or a function
|
||||
// or evaluvating an expression.
|
||||
typedef enum {
|
||||
PK_RESULT_SUCCESS = 0, // Successfully finished the execution.
|
||||
PK_RESULT_COMPILE_ERROR, // Compilation failed.
|
||||
PK_RESULT_RUNTIME_ERROR, // An error occured at runtime.
|
||||
} PkInterpretResult;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG FUNCTION POINTERS & CALLBACKS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// C function pointer which is callable from PocketLang.
|
||||
typedef void (*pkNativeFn)(PKVM* vm);
|
||||
|
||||
// A function that'll be called for all the allocation calls by PKVM.
|
||||
//
|
||||
@ -77,43 +133,18 @@ typedef struct PKVM PKVM;
|
||||
// function will return NULL.
|
||||
typedef void* (*pkReallocFn)(void* memory, size_t new_size, void* user_data);
|
||||
|
||||
// C function pointer which is callable from MiniScript.
|
||||
typedef void (*pkNativeFn)(PKVM* vm);
|
||||
|
||||
typedef enum {
|
||||
|
||||
// Compile time errors (syntax errors, unresolved fn, etc).
|
||||
PK_ERROR_COMPILE = 0,
|
||||
|
||||
// Runtime error message.
|
||||
PK_ERROR_RUNTIME,
|
||||
|
||||
// One entry of a runtime error stack.
|
||||
PK_ERROR_STACKTRACE,
|
||||
} PKErrorType;
|
||||
|
||||
// Error callback function pointer. for runtime error it'll call first with
|
||||
// PK_ERROR_RUNTIME followed by multiple callbacks with PK_ERROR_STACKTRACE.
|
||||
typedef void (*pkErrorFn) (PKVM* vm, PKErrorType type,
|
||||
typedef void (*pkErrorFn) (PKVM* vm, PkErrorType type,
|
||||
const char* file, int line,
|
||||
const char* message);
|
||||
|
||||
// A function callback used by `print()` statement.
|
||||
typedef void (*pkWriteFn) (PKVM* vm, const char* text);
|
||||
|
||||
typedef struct pkStringPtr pkStringPtr;
|
||||
|
||||
// A function callback symbol for clean/free the pkStringResult.
|
||||
typedef void (*pkResultDoneFn) (PKVM* vm, pkStringPtr result);
|
||||
|
||||
// A string pointer wrapper to pass cstring around with a on_done() callback
|
||||
// to clean it when the user of the string done with the string.
|
||||
struct pkStringPtr {
|
||||
const char* string; //< The string result.
|
||||
pkResultDoneFn on_done; //< Called once vm done with the string.
|
||||
void* user_data; //< User related data.
|
||||
};
|
||||
|
||||
// A function callback to resolve the import script name from the [from] path
|
||||
// to an absolute (or relative to the cwd). This is required to solve same
|
||||
// script imported with different relative path. Set the string attribute to
|
||||
@ -126,11 +157,73 @@ typedef pkStringPtr(*pkResolvePathFn) (PKVM* vm, const char* from,
|
||||
// to indicate if it's failed to load the script.
|
||||
typedef pkStringPtr(*pkLoadScriptFn) (PKVM* vm, const char* path);
|
||||
|
||||
// This function will be called once it done with the loaded script only if
|
||||
// it's corresponding MSLoadScriptResult is succeeded (ie. is_failed = false).
|
||||
//typedef void (*pkLoadDoneFn) (PKVM* vm, pkStringResult result);
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// Create a new pkConfiguraition with the default values and return it.
|
||||
// Override those default configuration to adopt to another hosting
|
||||
// application.
|
||||
PK_PUBLIC pkConfiguration pkNewConfiguration();
|
||||
|
||||
// Allocate initialize and returns a new VM
|
||||
PK_PUBLIC PKVM* pkNewVM(pkConfiguration* config);
|
||||
|
||||
// Clean the VM and dispose all the resources allocated by the VM.
|
||||
PK_PUBLIC void pkFreeVM(PKVM* vm);
|
||||
|
||||
// Update the user data of the vm.
|
||||
PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);
|
||||
|
||||
// Returns the associated user data.
|
||||
PK_PUBLIC void* pkGetUserData(PKVM* vm);
|
||||
|
||||
// Create a new handle for the [value]. This is usefull to keep the [value]
|
||||
// alive once it aquired from the stack. Do not use the [value] once creating
|
||||
// a new handle for it instead get the value from the handle by using
|
||||
// pkGetHandleValue() function.
|
||||
PK_PUBLIC PkHandle* pkNewHandle(PKVM* vm, PkVar value);
|
||||
|
||||
// Return the PkVar pointer in the handle, the returned pointer will be valid
|
||||
// till the handle is released.
|
||||
PK_PUBLIC PkVar pkGetHandleValue(PkHandle* handle);
|
||||
|
||||
// Release the handle and allow it's value to be garbage collected. Always call
|
||||
// this for every handles before freeing the VM.
|
||||
PK_PUBLIC void pkReleaseHandle(PKVM* vm, PkHandle* handle);
|
||||
|
||||
// Add a new module named [name] to the [vm]. Note that the module shouldn't
|
||||
// already existed, otherwise an assertion will fail to indicate that.
|
||||
PK_PUBLIC PkHandle* pkNewModule(PKVM* vm, const char* name);
|
||||
|
||||
// Add a native function to the given script. If [arity] is -1 that means
|
||||
// The function has variadic parameters and use pkGetArgc() to get the argc.
|
||||
PK_PUBLIC void pkModuleAddFunction(PKVM* vm, PkHandle* module,
|
||||
const char* name,
|
||||
pkNativeFn fptr, int arity);
|
||||
|
||||
// Interpret the source and return the result.
|
||||
PK_PUBLIC PkInterpretResult pkInterpretSource(PKVM* vm,
|
||||
const char* source,
|
||||
const char* path);
|
||||
|
||||
// Compile and execut file at given path.
|
||||
PK_PUBLIC PkInterpretResult pkInterpret(PKVM* vm, const char* path);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG PUBLIC TYPE DEFINES */
|
||||
/*****************************************************************************/
|
||||
|
||||
// A string pointer wrapper to pass cstring from host application to pocketlang
|
||||
// vm, with a on_done() callback to clean it when the pocketlang vm done with
|
||||
// the string.
|
||||
struct pkStringPtr {
|
||||
const char* string; //< The string result.
|
||||
pkResultDoneFn on_done; //< Called once vm done with the string.
|
||||
void* user_data; //< User related data.
|
||||
};
|
||||
|
||||
struct pkConfiguration {
|
||||
|
||||
// The callback used to allocate, reallocate, and free. If the function
|
||||
// pointer is NULL it defaults to the VM's realloc(), free() wrappers.
|
||||
@ -144,57 +237,72 @@ typedef struct {
|
||||
|
||||
// User defined data associated with VM.
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
} pkConfiguration;
|
||||
|
||||
// Create a new pkConfiguraition with the default values and return it.
|
||||
// Override those default configuration to adopt to another hosting
|
||||
// application.
|
||||
PK_PUBLIC pkConfiguration pkNewConfiguration();
|
||||
|
||||
typedef enum {
|
||||
PK_RESULT_SUCCESS = 0,
|
||||
PK_RESULT_COMPILE_ERROR,
|
||||
PK_RESULT_RUNTIME_ERROR,
|
||||
} PKInterpretResult;
|
||||
|
||||
// Allocate initialize and returns a new VM
|
||||
PK_PUBLIC PKVM* pkNewVM(pkConfiguration* config);
|
||||
|
||||
// Clean the VM and dispose all the resources allocated by the VM.
|
||||
PK_PUBLIC void pkFreeVM(PKVM* vm);
|
||||
|
||||
// Interpret the source and return the result.
|
||||
PK_PUBLIC PKInterpretResult pkInterpretSource(PKVM* vm,
|
||||
const char* source,
|
||||
const char* path);
|
||||
|
||||
// Compile and execut file at given path.
|
||||
PK_PUBLIC PKInterpretResult pkInterpret(PKVM* vm, const char* path);
|
||||
/*****************************************************************************/
|
||||
/* NATIVE FUNCTION API */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Set a runtime error to vm.
|
||||
PK_PUBLIC void pkSetRuntimeError(PKVM* vm, const char* message);
|
||||
|
||||
// Returns the associated user data.
|
||||
PK_PUBLIC void* pkGetUserData(PKVM* vm);
|
||||
// Return the type of the [value] this will help to get the type of the
|
||||
// variable that was extracted from pkGetArg() earlier.
|
||||
PK_PUBLIC PkVarType pkGetValueType(PkVar value);
|
||||
|
||||
// Update the user data of the vm.
|
||||
PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);
|
||||
// Return the current functions argument count. This is needed for functions
|
||||
// registered with -1 argument count (which means variadic arguments).
|
||||
PK_PUBLIC int pkGetArgc(PKVM* vm);
|
||||
|
||||
// Encode types to var.
|
||||
// TODO: user need to use vmPushTempRoot() for strings.
|
||||
PK_PUBLIC Var pkVarBool(PKVM* vm, bool value);
|
||||
PK_PUBLIC Var pkVarNumber(PKVM* vm, double value);
|
||||
PK_PUBLIC Var pkVarString(PKVM* vm, const char* value);
|
||||
// Return the [arg] th argument as a PkVar. This pointer will only be
|
||||
// valid till the current function ends, because it points to the var at the
|
||||
// stack and it'll popped when the current call frame ended. Use handlers to
|
||||
// keep the var alive even after that.
|
||||
PK_PUBLIC PkVar pkGetArg(PKVM* vm, int arg);
|
||||
|
||||
// The below functions are used to extract the function arguments from the
|
||||
// stack as a type. They will first validate the argument's type and set a
|
||||
// runtime error if it's not and return false. Otherwise it'll set the [value]
|
||||
// with the extracted value. Note that the arguments are 1 based (to get the
|
||||
// first argument use 1 not 0).
|
||||
|
||||
PK_PUBLIC bool pkGetArgBool(PKVM* vm, int arg, bool* vlaue);
|
||||
PK_PUBLIC bool pkGetArgNumber(PKVM* vm, int arg, double* value);
|
||||
PK_PUBLIC bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value);
|
||||
|
||||
// The below functions are used to set the return value of the current native
|
||||
// function's. Don't use it outside a registered native function.
|
||||
|
||||
PK_PUBLIC void pkReturnNull(PKVM* vm);
|
||||
PK_PUBLIC void pkReturnBool(PKVM* vm, bool value);
|
||||
PK_PUBLIC void pkReturnNumber(PKVM* vm, double value);
|
||||
PK_PUBLIC void pkReturnValue(PKVM* vm, PkVar value);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG TYPE FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// The below functions will allocate a new object and return's it's value
|
||||
// wrapped around a handler.
|
||||
|
||||
PK_PUBLIC PkHandle* pkNewString(PKVM* vm, const char* value);
|
||||
PK_PUBLIC PkHandle* pkNewList(PKVM* vm);
|
||||
PK_PUBLIC PkHandle* pkNewMap(PKVM* vm);
|
||||
|
||||
PK_PUBLIC const char* pkStringGetData(PkVar value);
|
||||
|
||||
|
||||
// TODO:
|
||||
// The below functions will push the primitive values on the stack and return
|
||||
// it's pointer as a PkVar it's usefull to convert your primitive values as
|
||||
// pocketlang variables.
|
||||
//PK_PUBLIC PkVar pkPushNull(PKVM* vm);
|
||||
//PK_PUBLIC PkVar pkPushBool(PKVM* vm, bool value);
|
||||
//PK_PUBLIC PkVar pkPushNumber(PKVM* vm, double value);
|
||||
|
||||
// Decode var types.
|
||||
// TODO: const char* should be copied otherwise it'll become dangling pointer.
|
||||
PK_PUBLIC bool pkAsBool(PKVM* vm, Var value);
|
||||
PK_PUBLIC double pkAsNumber(PKVM* vm, Var value);
|
||||
PK_PUBLIC const char* pkAsString(PKVM* vm, Var value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // MINISCRIPT_H
|
||||
#endif // POCKETLANG_H
|
||||
|
93
src/var.c
93
src/var.c
@ -9,32 +9,57 @@
|
||||
#include "var.h"
|
||||
#include "vm.h"
|
||||
|
||||
// Public Api /////////////////////////////////////////////////////////////////
|
||||
Var pkVarBool(PKVM* vm, bool value) {
|
||||
return VAR_BOOL(value);
|
||||
/*****************************************************************************/
|
||||
/* PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
PkVarType pkGetValueType(PkVar value) {
|
||||
__ASSERT(value != NULL, "Given value was NULL.");
|
||||
|
||||
if (IS_NULL(*(Var*)(value))) return PK_NULL;
|
||||
if (IS_BOOL(*(Var*)(value))) return PK_BOOL;
|
||||
if (IS_NUM(*(Var*)(value))) return PK_NUMBER;
|
||||
|
||||
__ASSERT(IS_OBJ(*(Var*)(value)),
|
||||
"Invalid var pointer. Might be a dangling pointer");
|
||||
|
||||
Object* obj = AS_OBJ(*(Var*)(value));
|
||||
switch (obj->type) {
|
||||
case OBJ_STRING: return PK_STRING;
|
||||
case OBJ_LIST: return PK_LIST;
|
||||
case OBJ_MAP: return PK_MAP;
|
||||
case OBJ_RANGE: return PK_RANGE;
|
||||
case OBJ_SCRIPT: return PK_SCRIPT;
|
||||
case OBJ_FUNC: return PK_FUNCTION;
|
||||
case OBJ_FIBER: return PK_FIBER;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return (PkVarType)0;
|
||||
}
|
||||
|
||||
Var pkVarNumber(PKVM* vm, double value) {
|
||||
return VAR_NUM(value);
|
||||
PkHandle* pkNewString(PKVM* vm, const char* value) {
|
||||
return vmNewHandle(vm, VAR_OBJ(&newString(vm, value)->_super));
|
||||
}
|
||||
|
||||
Var pkVarString(PKVM* vm, const char* value) {
|
||||
return VAR_OBJ(newStringLength(vm, value, (uint32_t)strlen(value)));
|
||||
PkHandle* pkNewList(PKVM* vm) {
|
||||
return vmNewHandle(vm, VAR_OBJ(&newList(vm, MIN_CAPACITY)->_super));
|
||||
}
|
||||
|
||||
bool pkAsBool(PKVM* vm, Var value) {
|
||||
return AS_BOOL(value);
|
||||
PkHandle* pkNewMap(PKVM* vm) {
|
||||
return vmNewHandle(vm, VAR_OBJ(&newMap(vm)->_super));
|
||||
}
|
||||
|
||||
double pkAsNumber(PKVM* vm, Var value) {
|
||||
return AS_NUM(value);
|
||||
const char* pkStringGetData(PkVar value) {
|
||||
Var str = (*(Var*)value);
|
||||
__ASSERT(IS_OBJ(str) && AS_OBJ(str)->type == OBJ_STRING,
|
||||
"Value should be of type string.");
|
||||
return ((String*)AS_OBJ(str))->data;
|
||||
}
|
||||
|
||||
const char* pkAsString(PKVM* vm, Var value) {
|
||||
return AS_STRING(value)->data;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*****************************************************************************/
|
||||
/* VAR INTERNALS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Number of maximum digits for to_string buffer.
|
||||
#define TO_STRING_BUFF_SIZE 128
|
||||
@ -644,14 +669,26 @@ void freeObject(PKVM* vm, Object* self) {
|
||||
|
||||
// Utility functions //////////////////////////////////////////////////////////
|
||||
|
||||
const char* varTypeName(Var v) {
|
||||
if (IS_NULL(v)) return "null";
|
||||
if (IS_BOOL(v)) return "bool";
|
||||
if (IS_NUM(v)) return "number";
|
||||
const char* getPkVarTypeName(PkVarType type) {
|
||||
switch (type) {
|
||||
case PK_NULL: return "null";
|
||||
case PK_BOOL: return "bool";
|
||||
case PK_NUMBER: return "number";
|
||||
case PK_STRING: return "String";
|
||||
case PK_LIST: return "List";
|
||||
case PK_MAP: return "Map";
|
||||
case PK_RANGE: return "Range";
|
||||
case PK_SCRIPT: return "Script";
|
||||
case PK_FUNCTION: return "Function";
|
||||
case PK_FIBER: return "Fiber";
|
||||
}
|
||||
|
||||
ASSERT(IS_OBJ(v), OOPS);
|
||||
Object* obj = AS_OBJ(v);
|
||||
switch (obj->type) {
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* getObjectTypeName(ObjectType type) {
|
||||
switch (type) {
|
||||
case OBJ_STRING: return "String";
|
||||
case OBJ_LIST: return "List";
|
||||
case OBJ_MAP: return "Map";
|
||||
@ -665,6 +702,16 @@ const char* varTypeName(Var v) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* varTypeName(Var v) {
|
||||
if (IS_NULL(v)) return "null";
|
||||
if (IS_BOOL(v)) return "bool";
|
||||
if (IS_NUM(v)) return "number";
|
||||
|
||||
ASSERT(IS_OBJ(v), OOPS);
|
||||
Object* obj = AS_OBJ(v);
|
||||
return getObjectTypeName(obj->type);
|
||||
}
|
||||
|
||||
bool isValuesSame(Var v1, Var v2) {
|
||||
#if VAR_NAN_TAGGING
|
||||
// Bit representation of each values are unique so just compare the bits.
|
||||
|
13
src/var.h
13
src/var.h
@ -180,18 +180,15 @@ typedef struct {
|
||||
|
||||
#endif // VAR_NAN_TAGGING
|
||||
|
||||
typedef enum /* ObjectType */ {
|
||||
typedef enum {
|
||||
OBJ_STRING,
|
||||
OBJ_LIST,
|
||||
OBJ_MAP,
|
||||
OBJ_RANGE,
|
||||
|
||||
OBJ_SCRIPT,
|
||||
OBJ_FUNC,
|
||||
|
||||
OBJ_FIBER,
|
||||
|
||||
// TODO: remove OBJ_USER and implement handlers for that.
|
||||
// TODO:
|
||||
OBJ_USER,
|
||||
} ObjectType;
|
||||
|
||||
@ -433,6 +430,12 @@ void freeObject(PKVM* vm, Object* self);
|
||||
|
||||
// Utility functions //////////////////////////////////////////////////////////
|
||||
|
||||
// Returns the type name of the PkVarType enum value.
|
||||
const char* getPkVarTypeName(PkVarType type);
|
||||
|
||||
// Returns the type name of the ObjectType enum value.
|
||||
const char* getObjectTypeName(ObjectType type);
|
||||
|
||||
// Returns the type name of the var [v].
|
||||
const char* varTypeName(Var v);
|
||||
|
||||
|
56
src/vm.c
56
src/vm.c
@ -107,9 +107,41 @@ void pkFreeVM(PKVM* self) {
|
||||
self->gray_list = (Object**)self->config.realloc_fn(
|
||||
self->gray_list, 0, self->config.user_data);
|
||||
|
||||
// Tell the host application that it forget to release all of it's handles
|
||||
// before freeing the VM.
|
||||
__ASSERT(self->handles != NULL, "Not all handles were released.");
|
||||
|
||||
DEALLOCATE(self, self);
|
||||
}
|
||||
|
||||
PkHandle* pkNewHandle(PKVM* vm, PkVar value) {
|
||||
return vmNewHandle(vm, *((Var*)value));
|
||||
}
|
||||
|
||||
PkVar pkGetHandleValue(PkHandle* handle) {
|
||||
return (PkVar)&handle->value;
|
||||
}
|
||||
|
||||
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
|
||||
__ASSERT(handle != NULL, "Given handle was NULL.");
|
||||
|
||||
// If the handle is the head of the vm's handle chain set it to the next one.
|
||||
if (handle == vm->handles) {
|
||||
vm->handles = handle->next;
|
||||
}
|
||||
|
||||
// Remove the handle from the chain by connecting the both ends together.
|
||||
if (handle->next) handle->next->prev = handle->prev;
|
||||
if (handle->prev) handle->prev->next = handle->next;
|
||||
|
||||
// Free the handle.
|
||||
DEALLOCATE(vm, handle);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VM INTERNALS */
|
||||
/*****************************************************************************/
|
||||
|
||||
void vmPushTempRef(PKVM* self, Object* obj) {
|
||||
ASSERT(obj != NULL, "Cannot reference to NULL.");
|
||||
ASSERT(self->temp_reference_count < MAX_TEMP_REFERENCE,
|
||||
@ -122,6 +154,16 @@ void vmPopTempRef(PKVM* self) {
|
||||
self->temp_reference_count--;
|
||||
}
|
||||
|
||||
PkHandle* vmNewHandle(PKVM* self, Var value) {
|
||||
PkHandle* handle = (PkHandle*)ALLOCATE(self, PkHandle);
|
||||
handle->value = value;
|
||||
handle->prev = NULL;
|
||||
handle->next = self->handles;
|
||||
if (handle->next != NULL) handle->next->prev = handle;
|
||||
self->handles = handle;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void vmCollectGarbage(PKVM* self) {
|
||||
|
||||
// Reset VM's bytes_allocated value and count it again so that we don't
|
||||
@ -142,6 +184,11 @@ void vmCollectGarbage(PKVM* self) {
|
||||
grayObject(self, self->temp_reference[i]);
|
||||
}
|
||||
|
||||
// Mark the handles.
|
||||
for (PkHandle* handle = self->handles; handle != NULL; handle = handle->next) {
|
||||
grayValue(self, handle->value);
|
||||
}
|
||||
|
||||
// Garbage collection triggered at the middle of a compilation.
|
||||
if (self->compiler != NULL) {
|
||||
compilerMarkObjects(self, self->compiler);
|
||||
@ -326,6 +373,7 @@ static inline void pushCallFrame(PKVM* vm, Function* fn) {
|
||||
}
|
||||
|
||||
void pkSetRuntimeError(PKVM* vm, const char* message) {
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
vm->fiber->error = newString(vm, message);
|
||||
}
|
||||
|
||||
@ -349,7 +397,7 @@ void vmReportError(PKVM* vm) {
|
||||
|
||||
// This function is responsible to call on_done function if it's done with the
|
||||
// provided string pointers.
|
||||
static PKInterpretResult interpretSource(PKVM* vm, pkStringPtr source,
|
||||
static PkInterpretResult interpretSource(PKVM* vm, pkStringPtr source,
|
||||
pkStringPtr path) {
|
||||
String* path_name = newString(vm, path.string);
|
||||
if (path.on_done) path.on_done(vm, path);
|
||||
@ -376,7 +424,7 @@ static PKInterpretResult interpretSource(PKVM* vm, pkStringPtr source,
|
||||
return vmRunScript(vm, scr);
|
||||
}
|
||||
|
||||
PKInterpretResult pkInterpretSource(PKVM* vm, const char* source,
|
||||
PkInterpretResult pkInterpretSource(PKVM* vm, const char* source,
|
||||
const char* path) {
|
||||
// Call the internal interpretSource implementation.
|
||||
pkStringPtr source_ptr = { source, NULL, NULL };
|
||||
@ -384,7 +432,7 @@ PKInterpretResult pkInterpretSource(PKVM* vm, const char* source,
|
||||
return interpretSource(vm, source_ptr, path_ptr);
|
||||
}
|
||||
|
||||
PKInterpretResult pkInterpret(PKVM* vm, const char* path) {
|
||||
PkInterpretResult pkInterpret(PKVM* vm, const char* path) {
|
||||
|
||||
pkStringPtr resolved;
|
||||
resolved.string = path;
|
||||
@ -413,7 +461,7 @@ PKInterpretResult pkInterpret(PKVM* vm, const char* path) {
|
||||
return interpretSource(vm, source, resolved);
|
||||
}
|
||||
|
||||
PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
// Reference to the instruction pointer in the call frame.
|
||||
register uint8_t** ip;
|
||||
|
17
src/vm.h
17
src/vm.h
@ -32,6 +32,14 @@ typedef struct {
|
||||
Function* fn; //< Native function pointer.
|
||||
} BuiltinFn;
|
||||
|
||||
// A doubly link list of vars that have reference in the host application.
|
||||
struct PkHandle {
|
||||
Var value;
|
||||
|
||||
PkHandle* prev;
|
||||
PkHandle* next;
|
||||
};
|
||||
|
||||
struct PKVM {
|
||||
|
||||
// The first object in the link list of all heap allocated objects.
|
||||
@ -61,6 +69,9 @@ struct PKVM {
|
||||
Object* temp_reference[MAX_TEMP_REFERENCE];
|
||||
int temp_reference_count;
|
||||
|
||||
// Pointer to the first handle in the doubly linked list of handles.
|
||||
PkHandle* handles;
|
||||
|
||||
// VM's configurations.
|
||||
pkConfiguration config;
|
||||
|
||||
@ -109,10 +120,14 @@ void vmPushTempRef(PKVM* self, Object* obj);
|
||||
// Pop the top most object from temporary reference stack.
|
||||
void vmPopTempRef(PKVM* self);
|
||||
|
||||
// Create and return a new handle for the [value].
|
||||
PkHandle* vmNewHandle(PKVM* self, Var value);
|
||||
|
||||
// Trigger garbage collection manually.
|
||||
void vmCollectGarbage(PKVM* self);
|
||||
|
||||
|
||||
// Runs the script and return result.
|
||||
PKInterpretResult vmRunScript(PKVM* vm, Script* script);
|
||||
PkInterpretResult vmRunScript(PKVM* vm, Script* script);
|
||||
|
||||
#endif // VM_H
|
||||
|
@ -13,7 +13,7 @@ from path import *
|
||||
|
||||
import "basics.pk" ## will import all
|
||||
import "if.pk" as if_test
|
||||
from "chain_call.pk" import fn1, fn2 as f2, fn3
|
||||
from "functions.pk" import fn1, fn2 as f2, fn3
|
||||
|
||||
## If it has a module name it'll bind to that name.
|
||||
import 'import/module.pk'
|
||||
|
Loading…
Reference in New Issue
Block a user