Restoring JerryScript a bit cleaner
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
Console.print('This is called from JavaScript');
|
||||
|
||||
const platformNames = {
|
||||
[System.PLATFORM_LINUX]: 'Linux',
|
||||
[System.PLATFORM_KNULLI]: 'Knulli',
|
||||
[System.PLATFORM_PSP]: 'PSP',
|
||||
[System.PLATFORM_GAMECUBE]: 'GameCube',
|
||||
[System.PLATFORM_WII]: 'Wii',
|
||||
};
|
||||
|
||||
const platformName = platformNames[System.platform] || 'Unknown';
|
||||
Console.print('Platform: ' + platformName);
|
||||
@@ -0,0 +1,96 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Turn things off we don't need
|
||||
set(JERRY_CMDLINE OFF CACHE BOOL "" FORCE)
|
||||
set(JERRY_EXT ON CACHE BOOL "" FORCE)
|
||||
set(JERRY_DEBUGGER OFF CACHE BOOL "" FORCE)
|
||||
set(JERRY_BUILTIN_DATE OFF CACHE BOOL "" FORCE)
|
||||
set(ENABLE_LTO OFF CACHE BOOL "" FORCE)
|
||||
|
||||
# Fetch Jerry
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
jerryscript
|
||||
GIT_REPOSITORY https://git.wish.moe/YourWishes/jerryscript
|
||||
GIT_TAG float32-fix
|
||||
)
|
||||
FetchContent_MakeAvailable(jerryscript)
|
||||
|
||||
# Mark found
|
||||
set(jerryscript_FOUND ON)
|
||||
|
||||
# Define targets
|
||||
if(TARGET jerryscript-core)
|
||||
set(JERRY_CORE_TARGET jerryscript-core)
|
||||
elseif(TARGET jerry-core)
|
||||
set(JERRY_CORE_TARGET jerry-core)
|
||||
endif()
|
||||
|
||||
if(TARGET jerryscript-ext)
|
||||
set(JERRY_EXT_TARGET jerryscript-ext)
|
||||
elseif(TARGET jerry-ext)
|
||||
set(JERRY_EXT_TARGET jerry-ext)
|
||||
endif()
|
||||
|
||||
if(TARGET jerryscript-port-default)
|
||||
set(JERRY_PORT_TARGET jerryscript-port-default)
|
||||
elseif(TARGET jerry-port-default)
|
||||
set(JERRY_PORT_TARGET jerry-port-default)
|
||||
elseif(TARGET jerryscript-port)
|
||||
set(JERRY_PORT_TARGET jerryscript-port)
|
||||
elseif(TARGET jerry-port)
|
||||
set(JERRY_PORT_TARGET jerry-port)
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_CORE_TARGET)
|
||||
message(FATAL_ERROR "JerryScript core target not found")
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_EXT_TARGET)
|
||||
message(FATAL_ERROR "JerryScript ext target not found")
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_PORT_TARGET)
|
||||
message(FATAL_ERROR "JerryScript port target not found")
|
||||
endif()
|
||||
|
||||
foreach(tgt IN ITEMS
|
||||
${JERRY_CORE_TARGET}
|
||||
${JERRY_EXT_TARGET}
|
||||
${JERRY_PORT_TARGET}
|
||||
)
|
||||
if(TARGET ${tgt})
|
||||
set_property(TARGET ${tgt} PROPERTY INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
target_compile_definitions(${JERRY_CORE_TARGET} PRIVATE
|
||||
JERRY_NUMBER_TYPE_FLOAT64=0
|
||||
JERRY_BUILTIN_DATE=0
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Export include dirs through the targets
|
||||
target_include_directories(${JERRY_CORE_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-core/include
|
||||
)
|
||||
|
||||
target_include_directories(${JERRY_EXT_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-ext/include
|
||||
)
|
||||
|
||||
target_include_directories(${JERRY_PORT_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-port/default/include
|
||||
)
|
||||
|
||||
# Suppress JerryScript-only warning
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${JERRY_CORE_TARGET} PRIVATE
|
||||
-Wno-error
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(jerryscript::core ALIAS ${JERRY_CORE_TARGET})
|
||||
add_library(jerryscript::ext ALIAS ${JERRY_EXT_TARGET})
|
||||
add_library(jerryscript::port ALIAS ${JERRY_PORT_TARGET})
|
||||
@@ -34,6 +34,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_OPENGL
|
||||
DUSK_OPENGL_ES
|
||||
DUSK_LINUX
|
||||
DUSK_KNULLI
|
||||
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||
DUSK_DISPLAY_WIDTH_DEFAULT=640
|
||||
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||
|
||||
@@ -32,6 +32,15 @@ if(NOT yyjson_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT jerryscript_FOUND)
|
||||
find_package(jerryscript REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
jerryscript::core
|
||||
jerryscript::ext
|
||||
jerryscript::port
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DUSK_BACKTRACE)
|
||||
target_link_options(${DUSK_LIBRARY_TARGET_NAME} PUBLIC -rdynamic)
|
||||
target_compile_definitions(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||
@@ -69,6 +78,7 @@ add_subdirectory(input)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(physics)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(system)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(ui)
|
||||
|
||||
@@ -14,4 +14,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
# Subdirs
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(json)
|
||||
add_subdirectory(json)
|
||||
add_subdirectory(script)
|
||||
@@ -39,4 +39,10 @@ assetloadercallbacks_t ASSET_LOADER_CALLBACKS[ASSET_LOADER_TYPE_COUNT] = {
|
||||
.loadAsync = assetJsonLoaderAsync,
|
||||
.dispose = assetJsonDispose
|
||||
},
|
||||
|
||||
[ASSET_LOADER_TYPE_SCRIPT] = {
|
||||
.loadSync = assetScriptLoaderSync,
|
||||
.loadAsync = assetScriptLoaderAsync,
|
||||
.dispose = assetScriptDispose
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "asset/loader/display/assettilesetloader.h"
|
||||
#include "asset/loader/locale/assetlocaleloader.h"
|
||||
#include "asset/loader/json/assetjsonloader.h"
|
||||
#include "asset/loader/script/assetscriptloader.h"
|
||||
|
||||
typedef enum {
|
||||
ASSET_LOADER_TYPE_NULL,
|
||||
@@ -20,6 +21,7 @@ typedef enum {
|
||||
ASSET_LOADER_TYPE_TILESET,
|
||||
ASSET_LOADER_TYPE_LOCALE,
|
||||
ASSET_LOADER_TYPE_JSON,
|
||||
ASSET_LOADER_TYPE_SCRIPT,
|
||||
|
||||
ASSET_LOADER_TYPE_COUNT
|
||||
} assetloadertype_t;
|
||||
@@ -30,6 +32,7 @@ typedef union {
|
||||
assettilesetloaderinput_t tileset;
|
||||
assetlocaleloaderinput_t locale;
|
||||
assetjsonloaderinput_t json;
|
||||
assetscriptloaderinput_t script;
|
||||
} assetloaderinput_t;
|
||||
|
||||
typedef union {
|
||||
@@ -38,6 +41,7 @@ typedef union {
|
||||
assettilesetloaderloading_t tileset;
|
||||
assetlocaleloaderloading_t locale;
|
||||
assetjsonloaderloading_t json;
|
||||
assetscriptloaderloading_t script;
|
||||
} assetloaderloading_t;
|
||||
|
||||
typedef union {
|
||||
@@ -46,6 +50,7 @@ typedef union {
|
||||
assettilesetoutput_t tileset;
|
||||
assetlocaleoutput_t locale;
|
||||
assetjsonoutput_t json;
|
||||
assetscriptoutput_t script;
|
||||
} assetloaderoutput_t;
|
||||
|
||||
typedef struct assetloading_s assetloading_t;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
assetscriptloader.c
|
||||
)
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetscriptloader.h"
|
||||
#include "asset/loader/assetloading.h"
|
||||
#include "asset/loader/assetentry.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
errorret_t assetScriptLoaderAsync(assetloading_t *loading) {
|
||||
assertNotNull(loading, "Loading cannot be NULL");
|
||||
|
||||
if(loading->loading.script.state != ASSET_SCRIPT_LOADING_STATE_READ_FILE) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
assertNull(loading->loading.script.buffer, "Buffer already defined?");
|
||||
|
||||
assetfile_t *file = &loading->loading.script.file;
|
||||
assetLoaderErrorChain(loading, assetFileInit(file, loading->entry->name, NULL, NULL));
|
||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||
|
||||
size_t capacity = ASSET_SCRIPT_CHUNK_SIZE;
|
||||
uint8_t *buffer = memoryAllocate(capacity + 1);
|
||||
size_t offset = 0;
|
||||
|
||||
while(1) {
|
||||
if(offset + ASSET_SCRIPT_CHUNK_SIZE > capacity) {
|
||||
size_t oldCapacity = capacity + 1;
|
||||
capacity += ASSET_SCRIPT_CHUNK_SIZE;
|
||||
memoryResize((void **)&buffer, oldCapacity, capacity + 1);
|
||||
}
|
||||
assetLoaderErrorChain(loading, assetFileRead(
|
||||
file, buffer + offset, ASSET_SCRIPT_CHUNK_SIZE
|
||||
));
|
||||
size_t chunk = (size_t)file->lastRead;
|
||||
offset += chunk;
|
||||
if(chunk == 0) break;
|
||||
}
|
||||
|
||||
buffer[offset] = '\0';
|
||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
||||
|
||||
loading->loading.script.buffer = buffer;
|
||||
loading->loading.script.size = offset;
|
||||
loading->loading.script.state = ASSET_SCRIPT_LOADING_STATE_EXEC;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_SYNC;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetScriptLoaderSync(assetloading_t *loading) {
|
||||
assertNotNull(loading, "Loading cannot be NULL");
|
||||
assertTrue(loading->type == ASSET_LOADER_TYPE_SCRIPT, "Invalid type.");
|
||||
|
||||
switch(loading->loading.script.state) {
|
||||
case ASSET_SCRIPT_LOADING_STATE_INITIAL:
|
||||
loading->loading.script.state = ASSET_SCRIPT_LOADING_STATE_READ_FILE;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_ASYNC;
|
||||
errorOk();
|
||||
break;
|
||||
|
||||
case ASSET_SCRIPT_LOADING_STATE_EXEC:
|
||||
break;
|
||||
|
||||
default:
|
||||
errorOk();
|
||||
}
|
||||
|
||||
uint8_t *buffer = loading->loading.script.buffer;
|
||||
assertNotNull(buffer, "Script buffer should have been loaded by now.");
|
||||
|
||||
jerry_value_t result = jerry_eval(
|
||||
(const jerry_char_t *)buffer,
|
||||
loading->loading.script.size,
|
||||
JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
memoryFree(buffer);
|
||||
loading->loading.script.buffer = NULL;
|
||||
|
||||
if(jerry_value_is_exception(result)) {
|
||||
jerry_value_t errVal = jerry_exception_value(result, false);
|
||||
jerry_value_t errStr = jerry_value_to_string(errVal);
|
||||
char_t buf[256];
|
||||
jerry_size_t len = jerry_string_to_buffer(
|
||||
errStr, JERRY_ENCODING_UTF8, (jerry_char_t *)buf, sizeof(buf) - 1
|
||||
);
|
||||
buf[len] = '\0';
|
||||
jerry_value_free(errStr);
|
||||
jerry_value_free(errVal);
|
||||
jerry_value_free(result);
|
||||
assetLoaderErrorThrow(loading, "Script error in '%s': %s",
|
||||
loading->entry->name, buf
|
||||
);
|
||||
}
|
||||
|
||||
loading->entry->data.script = (assetscriptoutput_t)result;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_LOADED;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetScriptDispose(assetentry_t *entry) {
|
||||
assertNotNull(entry, "Asset entry cannot be NULL");
|
||||
assertTrue(entry->type == ASSET_LOADER_TYPE_SCRIPT, "Invalid type.");
|
||||
if(entry->data.script != 0) {
|
||||
jerry_value_free((jerry_value_t)entry->data.script);
|
||||
entry->data.script = 0;
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "asset/assetfile.h"
|
||||
|
||||
#define ASSET_SCRIPT_CHUNK_SIZE 1024
|
||||
|
||||
typedef struct assetloading_s assetloading_t;
|
||||
typedef struct assetentry_s assetentry_t;
|
||||
|
||||
typedef struct { void *nothing; } assetscriptloaderinput_t;
|
||||
typedef uint32_t assetscriptoutput_t;
|
||||
|
||||
typedef enum {
|
||||
ASSET_SCRIPT_LOADING_STATE_INITIAL,
|
||||
ASSET_SCRIPT_LOADING_STATE_READ_FILE,
|
||||
ASSET_SCRIPT_LOADING_STATE_EXEC,
|
||||
ASSET_SCRIPT_LOADING_STATE_DONE
|
||||
} assetscriptloadingstate_t;
|
||||
|
||||
typedef struct {
|
||||
assetfile_t file;
|
||||
assetscriptloadingstate_t state;
|
||||
uint8_t *buffer;
|
||||
size_t size;
|
||||
} assetscriptloaderloading_t;
|
||||
|
||||
errorret_t assetScriptLoaderAsync(assetloading_t *loading);
|
||||
errorret_t assetScriptLoaderSync(assetloading_t *loading);
|
||||
errorret_t assetScriptDispose(assetentry_t *entry);
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "network/network.h"
|
||||
#include "system/system.h"
|
||||
#include "console/console.h"
|
||||
#include "script/script.h"
|
||||
#include "item/backpack.h"
|
||||
#include "save/save.h"
|
||||
|
||||
@@ -54,9 +55,10 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
physicsManagerInit();
|
||||
errorChain(networkInit());
|
||||
|
||||
/* Run the init script. */
|
||||
errorChain(scriptInit());
|
||||
errorChain(scriptExecFile("init.js"));
|
||||
|
||||
consolePrint("Engine initialized");
|
||||
sceneSet(SCENE_TYPE_OVERWORLD);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -96,6 +98,7 @@ errorret_t engineDispose(void) {
|
||||
errorChain(displayDispose());
|
||||
// errorChain(saveDispose());
|
||||
errorChain(assetDispose());
|
||||
errorChain(scriptDispose());
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
script.c
|
||||
scriptproto.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(module)
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulebase.c
|
||||
)
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "console/console.h"
|
||||
|
||||
static scriptproto_t MODULE_CONSOLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleConsolePrint) {
|
||||
char_t buf[512];
|
||||
char_t msg[4096];
|
||||
size_t msgLen = 0;
|
||||
|
||||
for(jerry_length_t i = 0; i < argc; ++i) {
|
||||
jerry_value_t strVal = jerry_value_to_string(args[i]);
|
||||
moduleBaseToString(strVal, buf, sizeof(buf));
|
||||
jerry_value_free(strVal);
|
||||
|
||||
size_t partLen = strlen(buf);
|
||||
if(msgLen + partLen + 1 < sizeof(msg)) {
|
||||
stringCopy(msg + msgLen, buf, sizeof(msg) - msgLen);
|
||||
msgLen += partLen;
|
||||
}
|
||||
|
||||
if(i + 1 < argc && msgLen + 1 < sizeof(msg)) {
|
||||
msg[msgLen++] = '\t';
|
||||
msg[msgLen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
consolePrint("%s", msg);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleGetVisible) {
|
||||
return jerry_boolean(CONSOLE.visible);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleSetVisible) {
|
||||
moduleBaseRequireArgs(1);
|
||||
CONSOLE.visible = moduleBaseArgBool(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleConsoleInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CONSOLE_PROTO, "Console",
|
||||
sizeof(uint8_t), NULL
|
||||
);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_CONSOLE_PROTO, "print", moduleConsolePrint
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_CONSOLE_PROTO, "visible",
|
||||
moduleConsoleGetVisible, moduleConsoleSetVisible
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleConsoleDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CONSOLE_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "engine/engine.h"
|
||||
|
||||
static scriptproto_t MODULE_ENGINE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleEngineGetRunning) {
|
||||
return jerry_boolean(ENGINE.running);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEngineExit) {
|
||||
ENGINE.running = false;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleEngineInit(void) {
|
||||
scriptProtoInit(&MODULE_ENGINE_PROTO, "Engine", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_ENGINE_PROTO, "running",
|
||||
moduleEngineGetRunning, NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENGINE_PROTO, "exit", moduleEngineExit
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleEngineDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENGINE_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "input/input.h"
|
||||
#include "input/inputbutton.h"
|
||||
|
||||
static scriptproto_t MODULE_INPUT_PROTO;
|
||||
|
||||
/** Validates an inputaction_t argument and returns a type error if bad. */
|
||||
#define moduleInputRequireAction(i, ctx) do { \
|
||||
if(!jerry_value_is_number(args[(i)])) { \
|
||||
return moduleBaseThrow(ctx ": action must be a number"); \
|
||||
} \
|
||||
const inputaction_t _act = (inputaction_t)moduleBaseArgInt(i); \
|
||||
if(_act <= INPUT_ACTION_NULL || _act >= INPUT_ACTION_COUNT) { \
|
||||
return moduleBaseThrow(ctx ": invalid action"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
moduleBaseFunction(moduleInputIsDown) {
|
||||
moduleInputRequireAction(0, "Input.isDown");
|
||||
return jerry_boolean(
|
||||
inputIsDown((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputWasDown) {
|
||||
moduleInputRequireAction(0, "Input.wasDown");
|
||||
return jerry_boolean(
|
||||
inputWasDown((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputPressed) {
|
||||
moduleInputRequireAction(0, "Input.pressed");
|
||||
return jerry_boolean(
|
||||
inputPressed((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputReleased) {
|
||||
moduleInputRequireAction(0, "Input.released");
|
||||
return jerry_boolean(
|
||||
inputReleased((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputGetValue) {
|
||||
moduleInputRequireAction(0, "Input.getValue");
|
||||
return jerry_number(
|
||||
inputGetCurrentValue((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputAxis) {
|
||||
moduleInputRequireAction(0, "Input.axis");
|
||||
moduleInputRequireAction(1, "Input.axis");
|
||||
return jerry_number(inputAxis(
|
||||
(inputaction_t)moduleBaseArgInt(0),
|
||||
(inputaction_t)moduleBaseArgInt(1)
|
||||
));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputBind) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
if(!jerry_value_is_number(args[1])) {
|
||||
return moduleBaseThrow("Input.bind: action must be a number");
|
||||
}
|
||||
const inputaction_t action = (inputaction_t)moduleBaseArgInt(1);
|
||||
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
|
||||
return moduleBaseThrow("Input.bind: invalid action");
|
||||
}
|
||||
|
||||
char_t name[128];
|
||||
moduleBaseToString(args[0], name, sizeof(name));
|
||||
if(name[0] == '\0') {
|
||||
return moduleBaseThrow("Input.bind: button name cannot be empty");
|
||||
}
|
||||
|
||||
inputbutton_t btn = inputButtonGetByName(name);
|
||||
if(btn.type == INPUT_BUTTON_TYPE_NONE) {
|
||||
return moduleBaseThrow("Input.bind: unknown button name");
|
||||
}
|
||||
|
||||
inputBind(btn, action);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleInputInit(void) {
|
||||
scriptProtoInit(&MODULE_INPUT_PROTO, "Input", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "isDown", moduleInputIsDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "wasDown", moduleInputWasDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "pressed", moduleInputPressed
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "released", moduleInputReleased
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "getValue", moduleInputGetValue
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "axis", moduleInputAxis
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "bind", moduleInputBind
|
||||
);
|
||||
|
||||
/* Register INPUT_ACTION_* integer constants into the global scope. */
|
||||
jerry_value_t result = jerry_eval(
|
||||
(const jerry_char_t *)INPUT_ACTION_SCRIPT,
|
||||
strlen(INPUT_ACTION_SCRIPT),
|
||||
JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
static void moduleInputDispose(void) {
|
||||
scriptProtoDispose(&MODULE_INPUT_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulebase.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
jerry_object_native_info_t MODULE_BASE_NATIVE_INFO = {
|
||||
.free_cb = moduleBaseFreeProto,
|
||||
.number_of_references = 0,
|
||||
.offset_of_references = 0
|
||||
};
|
||||
|
||||
void moduleBaseFreeProto(void *ptr, jerry_object_native_info_t *info) {
|
||||
assertNotNull(ptr, "Pointer must not be null");
|
||||
assertNotNull(info, "Native info must not be null");
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
jerry_value_t moduleBaseThrow(const char_t *message) {
|
||||
assertStrLenMin(message, 1, "Error message must not be empty");
|
||||
return jerry_throw_sz(JERRY_ERROR_TYPE, message);
|
||||
}
|
||||
|
||||
jerry_value_t moduleBaseThrowError(const errorret_t err) {
|
||||
assertNotNull(err.state, "Error state must not be NULL");
|
||||
assertNotNull(err.state->message, "Error message must not be NULL");
|
||||
jerry_value_t jsErr = jerry_throw_sz(JERRY_ERROR_TYPE, err.state->message);
|
||||
errorCatch(err);
|
||||
return jsErr;
|
||||
}
|
||||
|
||||
void moduleBaseToString(jerry_value_t val, char_t *buf, jerry_size_t buflen) {
|
||||
jerry_size_t len = jerry_string_to_buffer(
|
||||
val, JERRY_ENCODING_UTF8, (jerry_char_t *)buf, buflen - 1
|
||||
);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
void moduleBaseExceptionMessage(
|
||||
jerry_value_t exception,
|
||||
char_t *buf,
|
||||
size_t buflen
|
||||
) {
|
||||
jerry_value_t errVal = jerry_exception_value(exception, false);
|
||||
jerry_value_t errStr = jerry_value_to_string(errVal);
|
||||
jerry_size_t len = jerry_string_to_buffer(
|
||||
errStr, JERRY_ENCODING_UTF8, (jerry_char_t *)buf, (jerry_size_t)(buflen - 1)
|
||||
);
|
||||
buf[len] = '\0';
|
||||
jerry_value_free(errStr);
|
||||
jerry_value_free(errVal);
|
||||
}
|
||||
|
||||
void moduleBaseDefineMethod(
|
||||
jerry_value_t obj,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t func = jerry_function_external(fn);
|
||||
jerry_object_set(obj, key, func);
|
||||
jerry_value_free(func);
|
||||
jerry_value_free(key);
|
||||
}
|
||||
|
||||
void moduleBaseDefineGlobalMethod(
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
moduleBaseDefineMethod(global, name, fn);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
|
||||
void moduleBaseSetValue(const char_t *name, jerry_value_t value) {
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_object_set(global, key, value);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
|
||||
jerry_value_t moduleBaseWrapPointer(void *ptr) {
|
||||
jerry_value_t obj = jerry_object();
|
||||
jerry_object_set_native_ptr(obj, &MODULE_BASE_NATIVE_INFO, ptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void *moduleBaseUnwrapPointer(jerry_value_t val) {
|
||||
if(!jerry_value_is_object(val)) return NULL;
|
||||
return jerry_object_get_native_ptr(val, &MODULE_BASE_NATIVE_INFO);
|
||||
}
|
||||
|
||||
jerry_value_t moduleBaseGetProp(
|
||||
jerry_value_t obj, const char_t *name
|
||||
) {
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t val = jerry_object_get(obj, key);
|
||||
jerry_value_free(key);
|
||||
return val;
|
||||
}
|
||||
|
||||
float_t moduleBaseValueFloat(jerry_value_t val) {
|
||||
return (float_t)jerry_value_as_number(val);
|
||||
}
|
||||
|
||||
int32_t moduleBaseValueInt(jerry_value_t val) {
|
||||
return (int32_t)jerry_value_as_number(val);
|
||||
}
|
||||
|
||||
void moduleBaseSetNumber(const char_t *name, double value) {
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t val = jerry_number(value);
|
||||
jerry_object_set(global, key, val);
|
||||
jerry_value_free(val);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
|
||||
void moduleBaseSetInt(const char_t *name, int32_t value) {
|
||||
moduleBaseSetNumber(name, (double)value);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/string.h"
|
||||
#include <jerryscript.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern jerry_object_native_info_t MODULE_BASE_NATIVE_INFO;
|
||||
|
||||
/**
|
||||
* Frees a native pointer associated with a JavaScript object, uses the internal
|
||||
* memory functions.
|
||||
*
|
||||
* @param ptr The native pointer to free. Must not be NULL.
|
||||
* @param info The native info associated with the pointer. Must not be NULL.
|
||||
*/
|
||||
void moduleBaseFreeProto(void *ptr, jerry_object_native_info_t *info);
|
||||
|
||||
/**
|
||||
* Throws a JavaScript error with the given message.
|
||||
*
|
||||
* @param message The error message to throw. Must not be empty.
|
||||
* @return A jerry_value_t representing the thrown error.
|
||||
*/
|
||||
jerry_value_t moduleBaseThrow(const char_t *message);
|
||||
|
||||
/**
|
||||
* "Converts" a dusk error to a jerry type error.
|
||||
*
|
||||
* @param err Native dusk error to convert.
|
||||
* @return A jerry_value_t representing the thrown error.
|
||||
*/
|
||||
jerry_value_t moduleBaseThrowError(const errorret_t err);
|
||||
|
||||
/**
|
||||
* Converts a jerry value to a string and writes it to the provided buffer.
|
||||
*
|
||||
* @param val The jerry value to convert.
|
||||
* @param buf The buffer to write the string to.
|
||||
* @param buflen The length of the buffer.
|
||||
*/
|
||||
void moduleBaseToString(jerry_value_t val, char_t *buf, jerry_size_t buflen);
|
||||
|
||||
/**
|
||||
* Converts a jerry exception value to a string and writes it to the provided
|
||||
* buffer.
|
||||
*
|
||||
* @param exception The jerry exception value to convert.
|
||||
* @param buf The buffer to write the string to.
|
||||
* @param buflen The length of the buffer.
|
||||
*/
|
||||
void moduleBaseExceptionMessage(
|
||||
jerry_value_t exception,
|
||||
char_t *buf,
|
||||
size_t buflen
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a method on a given object.
|
||||
*
|
||||
* @param obj The object to define the method on.
|
||||
* @param name The name of the method.
|
||||
* @param fn The function pointer to the method implementation.
|
||||
*/
|
||||
void moduleBaseDefineMethod(
|
||||
jerry_value_t obj,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a global method.
|
||||
*
|
||||
* @param name The name of the method.
|
||||
* @param fn The function pointer to the method implementation.
|
||||
*/
|
||||
void moduleBaseDefineGlobalMethod(
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets a global variable to a given jerry value.
|
||||
*
|
||||
* @param name The name of the global variable.
|
||||
* @param value The jerry value to set the variable to.
|
||||
*/
|
||||
void moduleBaseSetValue(const char_t *name, jerry_value_t value);
|
||||
|
||||
/**
|
||||
* Wraps a native pointer in a jerry object.
|
||||
*
|
||||
* @param ptr The native pointer to wrap.
|
||||
* @return A jerry_value_t representing the wrapped pointer.
|
||||
*/
|
||||
jerry_value_t moduleBaseWrapPointer(void *ptr);
|
||||
|
||||
/**
|
||||
* Unwraps a native pointer from a jerry object.
|
||||
*
|
||||
* @param val The jerry value to unwrap the pointer from.
|
||||
* @return The unwrapped native pointer.
|
||||
*/
|
||||
void *moduleBaseUnwrapPointer(jerry_value_t val);
|
||||
|
||||
/**
|
||||
* Gets a property from a jerry object as a jerry value.
|
||||
*
|
||||
* @param obj The object to get the property from.
|
||||
* @param name The name of the property to get.
|
||||
* @return The value of the property.
|
||||
*/
|
||||
jerry_value_t moduleBaseGetProp(
|
||||
jerry_value_t obj, const char_t *name
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts a jerry value to a float.
|
||||
*
|
||||
* @param val The jerry value to convert.
|
||||
* @return The converted float value.
|
||||
*/
|
||||
float_t moduleBaseValueFloat(jerry_value_t val);
|
||||
|
||||
/**
|
||||
* Converts a jerry value to an int.
|
||||
*
|
||||
* @param val The jerry value to convert.
|
||||
* @return The converted int value.
|
||||
*/
|
||||
int32_t moduleBaseValueInt(jerry_value_t val);
|
||||
|
||||
/**
|
||||
* Sets a global variable to a given number value.
|
||||
*
|
||||
* @param name The name of the global variable.
|
||||
* @param value The number value to set the variable to.
|
||||
*/
|
||||
void moduleBaseSetNumber(const char_t *name, double value);
|
||||
|
||||
/**
|
||||
* Sets a global variable to a given int value.
|
||||
*
|
||||
* @param name The name of the global variable.
|
||||
* @param value The int value to set the variable to.
|
||||
*/
|
||||
void moduleBaseSetInt(const char_t *name, int32_t value);
|
||||
|
||||
#define moduleBaseFunction(name) \
|
||||
static jerry_value_t name( \
|
||||
const jerry_call_info_t *callInfo, \
|
||||
const jerry_value_t args[], \
|
||||
const jerry_length_t argc)
|
||||
|
||||
#define moduleBaseRequireArgs(n) do { \
|
||||
if(argc < (jerry_length_t)(n)) { \
|
||||
return moduleBaseThrow("Expected at least " #n " argument(s)"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define moduleBaseRequireNumber(i) do { \
|
||||
if(!jerry_value_is_number(args[(i)])) { \
|
||||
return moduleBaseThrow("Expected number argument"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define moduleBaseRequireString(i) do { \
|
||||
if(!jerry_value_is_string(args[(i)])) { \
|
||||
return moduleBaseThrow("Expected string argument"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define moduleBaseArgFloat(i) ((float_t)jerry_value_as_number(args[(i)]))
|
||||
#define moduleBaseArgInt(i) ((int32_t)jerry_value_as_number(args[(i)]))
|
||||
#define moduleBaseArgBool(i) (jerry_value_is_true(args[(i)]))
|
||||
|
||||
#define moduleBaseOptFloat(i, def) \
|
||||
((jerry_length_t)(i) < argc && jerry_value_is_number(args[(i)]) \
|
||||
? (float_t)jerry_value_as_number(args[(i)]) : (def))
|
||||
|
||||
#define moduleBaseOptInt(i, def) \
|
||||
((jerry_length_t)(i) < argc && jerry_value_is_number(args[(i)]) \
|
||||
? (int32_t)jerry_value_as_number(args[(i)]) : (def))
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/console/moduleconsole.h"
|
||||
#include "script/module/engine/moduleengine.h"
|
||||
#include "script/module/input/moduleinput.h"
|
||||
#include "script/module/system/modulesystem.h"
|
||||
|
||||
static void moduleListInit(void) {
|
||||
moduleConsoleInit();
|
||||
moduleEngineInit();
|
||||
moduleInputInit();
|
||||
moduleSystemInit();
|
||||
}
|
||||
|
||||
static void moduleListDispose(void) {
|
||||
moduleSystemDispose();
|
||||
moduleInputDispose();
|
||||
moduleEngineDispose();
|
||||
moduleConsoleDispose();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "system/system.h"
|
||||
|
||||
static scriptproto_t MODULE_SYSTEM_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleSystemGetPlatform) {
|
||||
return jerry_number((double)systemGetPlatform());
|
||||
}
|
||||
|
||||
static void moduleSystemInit(void) {
|
||||
scriptProtoInit(&MODULE_SYSTEM_PROTO, "System", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SYSTEM_PROTO, "platform",
|
||||
moduleSystemGetPlatform, NULL
|
||||
);
|
||||
|
||||
/* Register PLATFORM_* integer constants on the System global. */
|
||||
jerry_value_t target = MODULE_SYSTEM_PROTO.prototype;
|
||||
|
||||
#define SYSTEM_PLATFORM(name, value) \
|
||||
do { \
|
||||
jerry_value_t key = jerry_string_sz("PLATFORM_" #name); \
|
||||
jerry_value_t val = jerry_number((double)(value)); \
|
||||
jerry_object_set(target, key, val); \
|
||||
jerry_value_free(val); \
|
||||
jerry_value_free(key); \
|
||||
} while(0);
|
||||
SYSTEM_PLATFORM_LIST
|
||||
#undef SYSTEM_PLATFORM
|
||||
}
|
||||
|
||||
static void moduleSystemDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SYSTEM_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "script.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "asset/loader/assetentry.h"
|
||||
#include "script/module/modulelist.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
script_t SCRIPT;
|
||||
|
||||
errorret_t scriptInit(void) {
|
||||
memoryZero(&SCRIPT, sizeof(script_t));
|
||||
|
||||
jerry_init(JERRY_INIT_EMPTY);
|
||||
SCRIPT.initialized = true;
|
||||
|
||||
moduleListInit();
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t scriptExecString(const char_t *source) {
|
||||
assertNotNull(source, "Source cannot be NULL");
|
||||
assertTrue(SCRIPT.initialized, "Script system not initialized");
|
||||
|
||||
jerry_value_t result = jerry_eval(
|
||||
(const jerry_char_t *)source,
|
||||
strlen(source),
|
||||
JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
|
||||
if(jerry_value_is_exception(result)) {
|
||||
char_t buf[256];
|
||||
jerry_value_t errVal = jerry_exception_value(result, false);
|
||||
jerry_value_t errStr = jerry_value_to_string(errVal);
|
||||
jerry_size_t len = jerry_string_to_buffer(
|
||||
errStr, JERRY_ENCODING_UTF8, (jerry_char_t *)buf, sizeof(buf) - 1
|
||||
);
|
||||
buf[len] = '\0';
|
||||
jerry_value_free(errStr);
|
||||
jerry_value_free(errVal);
|
||||
jerry_value_free(result);
|
||||
errorThrow("Script error: %s", buf);
|
||||
}
|
||||
|
||||
jerry_value_free(result);
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t scriptExecFile(const char_t *path) {
|
||||
assertNotNull(path, "Path cannot be NULL");
|
||||
assertTrue(SCRIPT.initialized, "Script system not initialized");
|
||||
|
||||
assetentry_t *entry = assetGetEntry(path, ASSET_LOADER_TYPE_SCRIPT, NULL);
|
||||
assertNotNull(entry, "Failed to get asset entry for script");
|
||||
errorChain(assetRequireLoaded(entry));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t scriptDispose(void) {
|
||||
if(!SCRIPT.initialized) errorOk();
|
||||
moduleListDispose();
|
||||
jerry_cleanup();
|
||||
SCRIPT.initialized = false;
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
bool_t initialized;
|
||||
} script_t;
|
||||
|
||||
extern script_t SCRIPT;
|
||||
|
||||
/**
|
||||
* Initializes the script system, starting up JerryScript and registering all
|
||||
* built-in modules.
|
||||
*
|
||||
* @return Any error that occurred.
|
||||
*/
|
||||
errorret_t scriptInit(void);
|
||||
|
||||
/**
|
||||
* Evaluates a JS source string in the global scope.
|
||||
*
|
||||
* @param source Null-terminated JS source to evaluate.
|
||||
* @return Any error that occurred.
|
||||
*/
|
||||
errorret_t scriptExecString(const char_t *source);
|
||||
|
||||
/**
|
||||
* Loads and evaluates a script asset from the archive. The result is cached
|
||||
* by the asset system; repeated calls with the same path do not re-execute.
|
||||
*
|
||||
* @param path Path of the script inside the asset archive.
|
||||
* @return Any error that occurred.
|
||||
*/
|
||||
errorret_t scriptExecFile(const char_t *path);
|
||||
|
||||
/**
|
||||
* Disposes of the script system and shuts down JerryScript.
|
||||
*
|
||||
* @return Any error that occurred.
|
||||
*/
|
||||
errorret_t scriptDispose(void);
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scriptproto.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "script/module/modulebase.h"
|
||||
|
||||
void scriptProtoInit(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
const size_t size,
|
||||
jerry_external_handler_t constructor
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
memoryZero(proto, sizeof(scriptproto_t));
|
||||
|
||||
proto->info = (jerry_object_native_info_t){
|
||||
.free_cb = moduleBaseFreeProto,
|
||||
.number_of_references = 0,
|
||||
.offset_of_references = 0
|
||||
};
|
||||
proto->prototype = jerry_object();
|
||||
proto->size = size;
|
||||
|
||||
if(constructor != NULL) {
|
||||
proto->constructor = jerry_function_external(constructor);
|
||||
jerry_value_t protoKey = jerry_string_sz("prototype");
|
||||
jerry_object_set(proto->constructor, protoKey, proto->prototype);
|
||||
jerry_value_free(protoKey);
|
||||
jerry_value_t ctorKey = jerry_string_sz("constructor");
|
||||
jerry_object_set(proto->prototype, ctorKey, proto->constructor);
|
||||
jerry_value_free(ctorKey);
|
||||
}
|
||||
|
||||
if(name != NULL) {
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t val = proto->constructor ? proto->constructor : proto->prototype;
|
||||
jerry_object_set(global, key, val);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
}
|
||||
|
||||
void scriptProtoDefineProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertStrLenMin(name, 1, "Property name must not be empty");
|
||||
assertNotNull(getter, "Getter must not be null");
|
||||
|
||||
jerry_property_descriptor_t desc;
|
||||
memoryZero(&desc, sizeof(desc));
|
||||
desc.flags = (uint16_t)(
|
||||
JERRY_PROP_IS_GET_DEFINED |
|
||||
JERRY_PROP_IS_ENUMERABLE_DEFINED | JERRY_PROP_IS_ENUMERABLE |
|
||||
JERRY_PROP_IS_CONFIGURABLE_DEFINED | JERRY_PROP_IS_CONFIGURABLE
|
||||
);
|
||||
desc.getter = jerry_function_external(getter);
|
||||
if(setter != NULL) {
|
||||
desc.flags |= JERRY_PROP_IS_SET_DEFINED;
|
||||
desc.setter = jerry_function_external(setter);
|
||||
}
|
||||
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t result = jerry_object_define_own_prop(proto->prototype, key, &desc);
|
||||
jerry_value_free(result);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(desc.getter);
|
||||
if(setter != NULL) jerry_value_free(desc.setter);
|
||||
}
|
||||
|
||||
void scriptProtoDefineFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertStrLenMin(name, 1, "Method name must not be empty");
|
||||
assertNotNull(fn, "Function handler must not be null");
|
||||
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t func = jerry_function_external(fn);
|
||||
jerry_object_set(proto->prototype, key, func);
|
||||
jerry_value_free(func);
|
||||
jerry_value_free(key);
|
||||
}
|
||||
|
||||
void scriptProtoDefineStaticProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertStrLenMin(name, 1, "Property name must not be empty");
|
||||
assertNotNull(getter, "Getter must not be null");
|
||||
|
||||
jerry_value_t target = (
|
||||
proto->constructor ? proto->constructor : proto->prototype
|
||||
);
|
||||
|
||||
jerry_property_descriptor_t desc;
|
||||
memoryZero(&desc, sizeof(desc));
|
||||
desc.flags = (uint16_t)(
|
||||
JERRY_PROP_IS_GET_DEFINED |
|
||||
JERRY_PROP_IS_ENUMERABLE_DEFINED | JERRY_PROP_IS_ENUMERABLE |
|
||||
JERRY_PROP_IS_CONFIGURABLE_DEFINED | JERRY_PROP_IS_CONFIGURABLE
|
||||
);
|
||||
desc.getter = jerry_function_external(getter);
|
||||
if(setter != NULL) {
|
||||
desc.flags |= JERRY_PROP_IS_SET_DEFINED;
|
||||
desc.setter = jerry_function_external(setter);
|
||||
}
|
||||
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t result = jerry_object_define_own_prop(target, key, &desc);
|
||||
jerry_value_free(result);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(desc.getter);
|
||||
if(setter != NULL) jerry_value_free(desc.setter);
|
||||
}
|
||||
|
||||
void scriptProtoDefineStaticFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertStrLenMin(name, 1, "Method name must not be empty");
|
||||
assertNotNull(fn, "Function handler must not be null");
|
||||
|
||||
jerry_value_t target = (
|
||||
proto->constructor ? proto->constructor : proto->prototype
|
||||
);
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t func = jerry_function_external(fn);
|
||||
jerry_object_set(target, key, func);
|
||||
jerry_value_free(func);
|
||||
jerry_value_free(key);
|
||||
}
|
||||
|
||||
jerry_value_t scriptProtoCreateValue(
|
||||
const scriptproto_t *proto,
|
||||
const void *value
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertNotNull(value, "Value pointer must not be null");
|
||||
|
||||
void *ptr = memoryAllocate(proto->size);
|
||||
memoryCopy(ptr, value, proto->size);
|
||||
jerry_value_t obj = jerry_object();
|
||||
jerry_object_set_native_ptr(obj, &proto->info, ptr);
|
||||
jerry_object_set_proto(obj, proto->prototype);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void *scriptProtoGetValue(
|
||||
const scriptproto_t *proto,
|
||||
const jerry_value_t obj
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
if(!jerry_value_is_object(obj)) return NULL;
|
||||
return jerry_object_get_native_ptr(obj, &proto->info);
|
||||
}
|
||||
|
||||
void scriptProtoDefineToString(
|
||||
scriptproto_t *proto,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
scriptProtoDefineFunc(proto, "toString", fn);
|
||||
}
|
||||
|
||||
void scriptProtoDispose(scriptproto_t *proto) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
jerry_value_free(proto->prototype);
|
||||
if(proto->constructor) jerry_value_free(proto->constructor);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
/**
|
||||
* Represents a JavaScript class prototype backed by a C struct.
|
||||
* Use scriptProtoInit() to populate, scriptProtoDispose() to clean up.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Native-info tag used to identify instances of this class. */
|
||||
jerry_object_native_info_t info;
|
||||
/** The JS prototype object shared by all instances. */
|
||||
jerry_value_t prototype;
|
||||
/** The JS constructor function, or 0 if no constructor was given. */
|
||||
jerry_value_t constructor;
|
||||
/** sizeof the C struct wrapped by each instance. */
|
||||
size_t size;
|
||||
} scriptproto_t;
|
||||
|
||||
/**
|
||||
* Initializes a JS class prototype.
|
||||
*
|
||||
* If name is non-NULL the class is registered as a global. When ctor is
|
||||
* also non-NULL the global is the constructor function (enabling
|
||||
* `new Name(...)`); otherwise the prototype object itself becomes the
|
||||
* global.
|
||||
*
|
||||
* @param proto The struct to initialize.
|
||||
* @param name JS global name, or NULL to skip global registration.
|
||||
* @param size sizeof the C struct this class wraps.
|
||||
* @param ctor Constructor handler, or NULL for no constructor.
|
||||
*/
|
||||
void scriptProtoInit(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
const size_t size,
|
||||
jerry_external_handler_t ctor
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines an instance property with a getter and optional setter.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Property name.
|
||||
* @param getter Getter handler (must not be NULL).
|
||||
* @param setter Setter handler, or NULL for a read-only property.
|
||||
*/
|
||||
void scriptProtoDefineProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines an instance method on the class prototype.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Method name.
|
||||
* @param fn C handler called when the method is invoked.
|
||||
*/
|
||||
void scriptProtoDefineFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a static property on the class (e.g. Console.visible).
|
||||
*
|
||||
* Attaches to the constructor when one exists, otherwise attaches
|
||||
* directly to the prototype object (which is the global in that case).
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Property name.
|
||||
* @param getter Getter handler (must not be NULL).
|
||||
* @param setter Setter handler, or NULL for a read-only property.
|
||||
*/
|
||||
void scriptProtoDefineStaticProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a static method on the class (e.g. Console.print).
|
||||
*
|
||||
* Attaches to the constructor when one exists, otherwise attaches
|
||||
* directly to the prototype object.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Method name.
|
||||
* @param fn C handler called when the static method is invoked.
|
||||
*/
|
||||
void scriptProtoDefineStaticFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a JS instance wrapping a copy of a C value.
|
||||
*
|
||||
* Allocates a copy of the value, sets it as native data on a new JS
|
||||
* object, and applies the class prototype.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param value Pointer to the C value to copy into the new JS object.
|
||||
* @return A new JS object with the class prototype and native data set.
|
||||
*/
|
||||
jerry_value_t scriptProtoCreateValue(
|
||||
const scriptproto_t *proto,
|
||||
const void *value
|
||||
);
|
||||
|
||||
/**
|
||||
* Unwraps the native C pointer from a JS object instance.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param obj The JS object to inspect.
|
||||
* @return Pointer to the wrapped C value, or NULL if not an instance.
|
||||
*/
|
||||
void *scriptProtoGetValue(
|
||||
const scriptproto_t *proto,
|
||||
const jerry_value_t obj
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a toString() method on the class prototype.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param fn C handler called when toString() is invoked on an
|
||||
* instance.
|
||||
*/
|
||||
void scriptProtoDefineToString(
|
||||
scriptproto_t *proto,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Releases all JerryScript resources held by the prototype.
|
||||
*
|
||||
* Must be called before jerry_cleanup() to avoid heap finalizer
|
||||
* crashes from live jerry_value_t GC roots.
|
||||
*
|
||||
* @param proto The class prototype to dispose.
|
||||
*/
|
||||
void scriptProtoDispose(scriptproto_t *proto);
|
||||
@@ -22,4 +22,18 @@ errorret_t systemInit() {
|
||||
|
||||
systemdialogtype_t systemGetActiveDialogType() {
|
||||
return systemGetActiveDialogTypePlatform();
|
||||
}
|
||||
|
||||
systemplatform_t systemGetPlatform(void) {
|
||||
#if defined(DUSK_KNULLI)
|
||||
return SYSTEM_PLATFORM_KNULLI;
|
||||
#elif defined(DUSK_PSP)
|
||||
return SYSTEM_PLATFORM_PSP;
|
||||
#elif defined(DUSK_GAMECUBE)
|
||||
return SYSTEM_PLATFORM_GAMECUBE;
|
||||
#elif defined(DUSK_WII)
|
||||
return SYSTEM_PLATFORM_WII;
|
||||
#else
|
||||
return SYSTEM_PLATFORM_LINUX;
|
||||
#endif
|
||||
}
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "system/systemplatformlist.h"
|
||||
|
||||
#define SYSTEM_PLATFORM(name, value) SYSTEM_PLATFORM_##name = value,
|
||||
typedef enum { SYSTEM_PLATFORM_LIST } systemplatform_t;
|
||||
#undef SYSTEM_PLATFORM
|
||||
|
||||
typedef enum {
|
||||
SYSTEM_DIALOG_TYPE_NONE,
|
||||
@@ -35,4 +40,11 @@ errorret_t systemInit(void);
|
||||
*
|
||||
* @return Dialog type currently open.
|
||||
*/
|
||||
systemdialogtype_t systemGetActiveDialogType();
|
||||
systemdialogtype_t systemGetActiveDialogType();
|
||||
|
||||
/**
|
||||
* Returns the platform the engine is currently running on.
|
||||
*
|
||||
* @return The current platform.
|
||||
*/
|
||||
systemplatform_t systemGetPlatform(void);
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* X-macro list of all supported platforms.
|
||||
* Usage: SYSTEM_PLATFORM(name, value)
|
||||
*
|
||||
* Example:
|
||||
* #define SYSTEM_PLATFORM(name, value) \
|
||||
* case SYSTEM_PLATFORM_##name: return #name;
|
||||
* SYSTEM_PLATFORM_LIST
|
||||
* #undef SYSTEM_PLATFORM
|
||||
*/
|
||||
#define SYSTEM_PLATFORM_LIST \
|
||||
SYSTEM_PLATFORM(LINUX, 0) \
|
||||
SYSTEM_PLATFORM(KNULLI, 1) \
|
||||
SYSTEM_PLATFORM(PSP, 2) \
|
||||
SYSTEM_PLATFORM(GAMECUBE, 3) \
|
||||
SYSTEM_PLATFORM(WII, 4)
|
||||
Reference in New Issue
Block a user