Basic script-based engine init is working - performance is poor
This commit is contained in:
196
core/engine.c
196
core/engine.c
@@ -1,66 +1,160 @@
|
||||
#include "engine.h"
|
||||
|
||||
#include "lib_engine.h"
|
||||
#include "lib_standard.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
#include "compiler.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
#include "console_colors.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//define the engine object
|
||||
Engine engine;
|
||||
|
||||
//errors here should be fatal
|
||||
static void error(Engine* engine, char* message) {
|
||||
static void fatalError(char* message) {
|
||||
fprintf(stderr, message);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//compilation functions
|
||||
//TODO: move these to their own file
|
||||
static char* readFile(char* path, size_t* fileSize) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fseek(file, 0L, SEEK_END);
|
||||
*fileSize = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = (char*)malloc(*fileSize + 1);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||
|
||||
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||
|
||||
if (bytesRead < *fileSize) {
|
||||
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static unsigned char* compileString(char* source, size_t* size) {
|
||||
Lexer lexer;
|
||||
Parser parser;
|
||||
Compiler compiler;
|
||||
|
||||
initLexer(&lexer, source);
|
||||
initParser(&parser, &lexer);
|
||||
initCompiler(&compiler);
|
||||
|
||||
//run the parser until the end of the source
|
||||
ASTNode* node = scanParser(&parser);
|
||||
while(node != NULL) {
|
||||
//pack up and leave
|
||||
if (node->type == AST_NODEERROR) {
|
||||
printf(ERROR "error node detected\n" RESET);
|
||||
freeNode(node);
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writeCompiler(&compiler, node);
|
||||
freeNode(node);
|
||||
node = scanParser(&parser);
|
||||
}
|
||||
|
||||
//get the bytecode dump
|
||||
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
|
||||
|
||||
//cleanup
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
//no lexer to clean up
|
||||
|
||||
//finally
|
||||
return tb;
|
||||
}
|
||||
|
||||
//exposed functions
|
||||
void initEngine(Engine* engine) {
|
||||
void initEngine() {
|
||||
//clear
|
||||
engine->root = NULL;
|
||||
engine->running = true;
|
||||
engine.rootNode = NULL;
|
||||
engine.running = false;
|
||||
engine.window = NULL;
|
||||
engine.renderer = NULL;
|
||||
|
||||
//init SDL
|
||||
if (SDL_Init(0) != 0) {
|
||||
error(engine, "Failed to initialize SDL2");
|
||||
fatalError("Failed to initialize SDL2");
|
||||
}
|
||||
|
||||
//init the window
|
||||
engine->window = SDL_CreateWindow(
|
||||
"Caption",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
engine->screenWidth,
|
||||
engine->screenHeight,
|
||||
SDL_WINDOW_RESIZABLE
|
||||
);
|
||||
//init Toy
|
||||
initInterpreter(&engine.interpreter);
|
||||
injectNativeHook(&engine.interpreter, "engine", hookEngine);
|
||||
injectNativeHook(&engine.interpreter, "standard", hookStandard);
|
||||
|
||||
if (engine->window == NULL) {
|
||||
error(engine, "Failed to initialize the window");
|
||||
}
|
||||
size_t size = 0;
|
||||
char* source = readFile("./assets/scripts/init.toy", &size);
|
||||
unsigned char* tb = compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
//init the renderer
|
||||
engine->renderer = SDL_CreateRenderer(engine->window, -1, 0);
|
||||
|
||||
if (engine->renderer == NULL) {
|
||||
error(engine, "Failed to initialize the renderer");
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
|
||||
SDL_RenderSetLogicalSize(engine->renderer, engine->screenWidth, engine->screenHeight);
|
||||
runInterpreter(&engine.interpreter, tb, size);
|
||||
}
|
||||
|
||||
void freeEngine(Engine* engine) {
|
||||
SDL_DestroyRenderer(engine->renderer);
|
||||
SDL_DestroyWindow(engine->window);
|
||||
void freeEngine() {
|
||||
SDL_DestroyRenderer(engine.renderer);
|
||||
SDL_DestroyWindow(engine.window);
|
||||
SDL_Quit();
|
||||
|
||||
engine->renderer = NULL;
|
||||
engine->window = NULL;
|
||||
//clear existing root node
|
||||
if (engine.rootNode != NULL) {
|
||||
callEngineNode(engine.rootNode, &engine.interpreter, "onFree");
|
||||
|
||||
freeEngineNode(engine.rootNode);
|
||||
FREE(EngineNode, engine.rootNode);
|
||||
|
||||
engine.rootNode = NULL;
|
||||
}
|
||||
|
||||
freeInterpreter(&engine.interpreter);
|
||||
|
||||
engine.renderer = NULL;
|
||||
engine.window = NULL;
|
||||
}
|
||||
|
||||
static void execStep(Engine* engine) {
|
||||
//DEBUG: for now, just poll events
|
||||
static void execStep() {
|
||||
//call onStep
|
||||
callEngineNode(engine.rootNode, &engine.interpreter, "onStep");
|
||||
|
||||
//poll events
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
//quit
|
||||
case SDL_QUIT: {
|
||||
engine->running = false;
|
||||
engine.running = false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -68,9 +162,9 @@ static void execStep(Engine* engine) {
|
||||
case SDL_WINDOWEVENT: {
|
||||
switch(event.window.event) {
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
engine->screenWidth = event.window.data1;
|
||||
engine->screenHeight = event.window.data2;
|
||||
SDL_RenderSetLogicalSize(engine->renderer, engine->screenWidth, engine->screenHeight);
|
||||
engine.screenWidth = event.window.data1;
|
||||
engine.screenHeight = event.window.data2;
|
||||
SDL_RenderSetLogicalSize(engine.renderer, engine.screenWidth, engine.screenHeight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -82,25 +176,29 @@ static void execStep(Engine* engine) {
|
||||
}
|
||||
|
||||
//the heart of the engine
|
||||
void execEngine(Engine* engine) {
|
||||
void execEngine() {
|
||||
if (!engine.running) {
|
||||
fatalError("Can't execute the engine (did you forget to initialize the screen?)");
|
||||
}
|
||||
|
||||
//set up time
|
||||
gettimeofday(&engine->realTime, NULL);
|
||||
engine->simTime = engine->realTime;
|
||||
gettimeofday(&engine.realTime, NULL);
|
||||
engine.simTime = engine.realTime;
|
||||
struct timeval delta = { .tv_sec = 0, .tv_usec = 1000 * 1000 / 60 }; //60 frames per second
|
||||
|
||||
while (engine->running) {
|
||||
while (engine.running) {
|
||||
//calc the time passed
|
||||
gettimeofday(&engine->realTime, NULL);
|
||||
gettimeofday(&engine.realTime, NULL);
|
||||
|
||||
//if not enough time has passed
|
||||
if (engine->simTime.tv_sec < engine->realTime.tv_sec && engine->simTime.tv_usec < engine->realTime.tv_usec) {
|
||||
if (engine.simTime.tv_sec < engine.realTime.tv_sec && engine.simTime.tv_usec < engine.realTime.tv_usec) {
|
||||
//while not enough time has passed
|
||||
while(engine->simTime.tv_sec < engine->realTime.tv_sec && engine->simTime.tv_usec < engine->realTime.tv_usec) {
|
||||
while(engine.simTime.tv_sec < engine.realTime.tv_sec && engine.simTime.tv_usec < engine.realTime.tv_usec) {
|
||||
//simulate the world
|
||||
execStep(engine);
|
||||
execStep();
|
||||
|
||||
//calc the time simulation
|
||||
timeradd(&delta, &engine->simTime, &engine->simTime);
|
||||
timeradd(&delta, &engine.simTime, &engine.simTime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -108,8 +206,8 @@ void execEngine(Engine* engine) {
|
||||
}
|
||||
|
||||
//render the world
|
||||
SDL_SetRenderDrawColor(engine->renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later
|
||||
SDL_RenderClear(engine->renderer); //NOTE: This line can be disabled later
|
||||
SDL_RenderPresent(engine->renderer);
|
||||
SDL_SetRenderDrawColor(engine.renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later
|
||||
SDL_RenderClear(engine.renderer); //NOTE: This line can be disabled later
|
||||
SDL_RenderPresent(engine.renderer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "engine_node.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
@@ -10,11 +11,14 @@
|
||||
//the base engine object, which represents the state of the game
|
||||
typedef struct _engine {
|
||||
//engine stuff
|
||||
EngineNode* root;
|
||||
EngineNode* rootNode;
|
||||
struct timeval simTime;
|
||||
struct timeval realTime;
|
||||
bool running;
|
||||
|
||||
//Toy stuff
|
||||
Interpreter interpreter;
|
||||
|
||||
//SDL stuff
|
||||
SDL_Window* window;
|
||||
SDL_Renderer* renderer;
|
||||
@@ -22,9 +26,11 @@ typedef struct _engine {
|
||||
int screenHeight;
|
||||
} Engine;
|
||||
|
||||
//APIs for initializing the engine
|
||||
CORE_API void initEngine(Engine* engine);
|
||||
CORE_API void freeEngine(Engine* engine);
|
||||
//extern singleton
|
||||
extern Engine engine;
|
||||
|
||||
CORE_API void execEngine(Engine* engine);
|
||||
//APIs for running the engine in main()
|
||||
CORE_API void initEngine();
|
||||
CORE_API void execEngine();
|
||||
CORE_API void freeEngine();
|
||||
|
||||
|
||||
258
core/lib_engine.c
Normal file
258
core/lib_engine.c
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "lib_engine.h"
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "literal_array.h"
|
||||
|
||||
//errors here should be fatal
|
||||
static void fatalError(char* message) {
|
||||
fprintf(stderr, message);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//compilation functions
|
||||
//TODO: move these to their own file
|
||||
#include "console_colors.h"
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
#include "compiler.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
static char* readFile(char* path, size_t* fileSize) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fseek(file, 0L, SEEK_END);
|
||||
*fileSize = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = (char*)malloc(*fileSize + 1);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||
|
||||
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||
|
||||
if (bytesRead < *fileSize) {
|
||||
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static unsigned char* compileString(char* source, size_t* size) {
|
||||
Lexer lexer;
|
||||
Parser parser;
|
||||
Compiler compiler;
|
||||
|
||||
initLexer(&lexer, source);
|
||||
initParser(&parser, &lexer);
|
||||
initCompiler(&compiler);
|
||||
|
||||
//run the parser until the end of the source
|
||||
ASTNode* node = scanParser(&parser);
|
||||
while(node != NULL) {
|
||||
//pack up and leave
|
||||
if (node->type == AST_NODEERROR) {
|
||||
printf(ERROR "error node detected\n" RESET);
|
||||
freeNode(node);
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writeCompiler(&compiler, node);
|
||||
freeNode(node);
|
||||
node = scanParser(&parser);
|
||||
}
|
||||
|
||||
//get the bytecode dump
|
||||
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
|
||||
|
||||
//cleanup
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
//no lexer to clean up
|
||||
|
||||
//finally
|
||||
return tb;
|
||||
}
|
||||
|
||||
//native functions to be called
|
||||
static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
if (engine.window != NULL) {
|
||||
fatalError("Can't re-initialize the window\n");
|
||||
}
|
||||
|
||||
if (arguments->count != 4) {
|
||||
fatalError("Incorrect number of arguments passed to initEngine\n");
|
||||
}
|
||||
|
||||
//extract the arguments
|
||||
Literal fscreen = popLiteralArray(arguments);
|
||||
Literal screenHeight = popLiteralArray(arguments);
|
||||
Literal screenWidth = popLiteralArray(arguments);
|
||||
Literal caption = popLiteralArray(arguments);
|
||||
|
||||
//check argument types
|
||||
if (!IS_STRING(caption) || !IS_INTEGER(screenWidth) || !IS_INTEGER(screenHeight) || !IS_BOOLEAN(fscreen)) {
|
||||
fatalError("Incorrect argument type passed to initEngine\n");
|
||||
}
|
||||
|
||||
//init the window
|
||||
engine.window = SDL_CreateWindow(
|
||||
AS_STRING(caption),
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
engine.screenWidth = AS_INTEGER(screenWidth),
|
||||
engine.screenHeight = AS_INTEGER(screenHeight),
|
||||
IS_TRUTHY(fscreen) ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE
|
||||
);
|
||||
|
||||
if (engine.window == NULL) {
|
||||
fatalError("Failed to initialize the window\n");
|
||||
}
|
||||
|
||||
//init the renderer
|
||||
engine.renderer = SDL_CreateRenderer(engine.window, -1, 0);
|
||||
|
||||
if (engine.renderer == NULL) {
|
||||
fatalError("Failed to initialize the renderer\n");
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
|
||||
SDL_RenderSetLogicalSize(engine.renderer, engine.screenWidth, engine.screenHeight);
|
||||
|
||||
//only run with a window
|
||||
engine.running = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments passed to loadRootNode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//extract the arguments
|
||||
Literal fname = popLiteralArray(arguments);
|
||||
|
||||
//check argument types
|
||||
if (!IS_STRING(fname)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n");
|
||||
freeLiteral(fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//clear existing root node
|
||||
if (engine.rootNode != NULL) {
|
||||
callEngineNode(engine.rootNode, &engine.interpreter, "onFree");
|
||||
|
||||
freeEngineNode(engine.rootNode);
|
||||
FREE(EngineNode, engine.rootNode);
|
||||
|
||||
engine.rootNode = NULL;
|
||||
}
|
||||
|
||||
//load the new root node
|
||||
size_t size = 0;
|
||||
char* source = readFile(AS_STRING(fname), &size);
|
||||
unsigned char* tb = compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
engine.rootNode = ALLOCATE(EngineNode, 1);
|
||||
|
||||
//BUGFIX: use an inner-interpreter here, otherwise it'll mess up the original's length value by calling run within a native function
|
||||
Interpreter inner;
|
||||
initInterpreter(&inner);
|
||||
|
||||
initEngineNode(engine.rootNode, &inner, tb, size);
|
||||
|
||||
freeInterpreter(&inner);
|
||||
|
||||
//init the new node
|
||||
callEngineNode(engine.rootNode, &engine.interpreter, "onInit");
|
||||
|
||||
//cleanup
|
||||
freeLiteral(fname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//call the hook
|
||||
typedef struct Natives {
|
||||
char* name;
|
||||
NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
|
||||
//build the natives list
|
||||
Natives natives[] = {
|
||||
{"initWindow", nativeInitWindow},
|
||||
{"loadRootNode", nativeLoadRootNode},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
//store the library in an aliased dictionary
|
||||
if (!IS_NULL(alias)) {
|
||||
//make sure the name isn't taken
|
||||
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
|
||||
interpreter->errorOutput("Can't override an existing variable\n");
|
||||
freeLiteral(alias);
|
||||
return false;
|
||||
}
|
||||
|
||||
//create the dictionary to load up with functions
|
||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
||||
initLiteralDictionary(dictionary);
|
||||
|
||||
//load the dict with functions
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name));
|
||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||
func.type = LITERAL_FUNCTION_NATIVE;
|
||||
|
||||
setLiteralDictionary(dictionary, name, func);
|
||||
|
||||
freeLiteral(name);
|
||||
freeLiteral(func);
|
||||
}
|
||||
|
||||
//build the type
|
||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
|
||||
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
|
||||
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
|
||||
TYPE_PUSH_SUBTYPE(&type, strType);
|
||||
TYPE_PUSH_SUBTYPE(&type, fnType);
|
||||
|
||||
//set scope
|
||||
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
|
||||
declareScopeVariable(interpreter->scope, alias, type);
|
||||
setScopeVariable(interpreter->scope, alias, dict, false);
|
||||
|
||||
//cleanup
|
||||
freeLiteral(dict);
|
||||
freeLiteral(type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//default
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
core/lib_engine.h
Normal file
6
core/lib_engine.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias);
|
||||
|
||||
94
core/lib_standard.c
Normal file
94
core/lib_standard.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "lib_standard.h"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 0) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to clock\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the time from C (what a pain)
|
||||
time_t rawtime = time(NULL);
|
||||
struct tm* timeinfo = localtime( &rawtime );
|
||||
char* timestr = asctime(timeinfo);
|
||||
|
||||
//push to the stack
|
||||
int len = strlen(timestr) - 1; //-1 for the newline
|
||||
Literal timeLiteral = TO_STRING_LITERAL(copyString(timestr, len), len);
|
||||
|
||||
//push to the stack
|
||||
pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||
|
||||
//cleanup
|
||||
freeLiteral(timeLiteral);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//call the hook
|
||||
typedef struct Natives {
|
||||
char* name;
|
||||
NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
|
||||
//build the natives list
|
||||
Natives natives[] = {
|
||||
{"clock", nativeClock},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
//store the library in an aliased dictionary
|
||||
if (!IS_NULL(alias)) {
|
||||
//make sure the name isn't taken
|
||||
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
|
||||
interpreter->errorOutput("Can't override an existing variable\n");
|
||||
freeLiteral(alias);
|
||||
return false;
|
||||
}
|
||||
|
||||
//create the dictionary to load up with functions
|
||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
||||
initLiteralDictionary(dictionary);
|
||||
|
||||
//load the dict with functions
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name));
|
||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||
func.type = LITERAL_FUNCTION_NATIVE;
|
||||
|
||||
setLiteralDictionary(dictionary, name, func);
|
||||
|
||||
freeLiteral(name);
|
||||
freeLiteral(func);
|
||||
}
|
||||
|
||||
//build the type
|
||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
|
||||
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
|
||||
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
|
||||
TYPE_PUSH_SUBTYPE(&type, strType);
|
||||
TYPE_PUSH_SUBTYPE(&type, fnType);
|
||||
|
||||
//set scope
|
||||
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
|
||||
declareScopeVariable(interpreter->scope, alias, type);
|
||||
setScopeVariable(interpreter->scope, alias, dict, false);
|
||||
|
||||
//cleanup
|
||||
freeLiteral(dict);
|
||||
freeLiteral(type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//default
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
core/lib_standard.h
Normal file
6
core/lib_standard.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias);
|
||||
|
||||
Reference in New Issue
Block a user