Renamed everything to fit the new naming scheme

This commit is contained in:
2023-01-26 21:12:44 +00:00
parent 3e18baeec0
commit f7f9e75ad9
21 changed files with 1883 additions and 580 deletions

View File

@@ -1,4 +1,4 @@
#include "core_common.h" #include "box_common.h"
STATIC_ASSERT(sizeof(char) == 1); STATIC_ASSERT(sizeof(char) == 1);
STATIC_ASSERT(sizeof(short) == 2); STATIC_ASSERT(sizeof(short) == 2);

View File

@@ -9,10 +9,10 @@
//platform exports/imports //platform exports/imports
#if defined(__linux__) #if defined(__linux__)
#define CORE_API extern #define BOX_API extern
#else #else
#define CORE_API #define BOX_API
#endif #endif

View File

@@ -1,4 +1,4 @@
#include "engine.h" #include "box_engine.h"
#include "lib_engine.h" #include "lib_engine.h"
#include "lib_input.h" #include "lib_input.h"
@@ -8,31 +8,31 @@
#include "lib_runner.h" #include "lib_runner.h"
#include "repl_tools.h" #include "repl_tools.h"
#include "memory.h" #include "toy_memory.h"
#include "lexer.h" #include "toy_lexer.h"
#include "parser.h" #include "toy_parser.h"
#include "compiler.h" #include "toy_compiler.h"
#include "interpreter.h" #include "toy_interpreter.h"
#include "literal_array.h" #include "toy_literal_array.h"
#include "literal_dictionary.h" #include "toy_literal_dictionary.h"
#include "console_colors.h" #include "toy_console_colors.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
//define the extern engine object //define the extern engine object
Engine engine; Box_Engine engine;
//errors here should be fatal //errors here should be fatal
static void fatalError(char* message) { static void fatalError(char* message) {
fprintf(stderr, "%s", message); fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, message);
exit(-1); exit(-1);
} }
//exposed functions //exposed functions
void initEngine() { void Box_initEngine() {
//clear //clear
engine.rootNode = NULL; engine.rootNode = NULL;
engine.running = false; engine.running = false;
@@ -45,45 +45,45 @@ void initEngine() {
} }
//init events //init events
initLiteralArray(&engine.keyDownEvents); Toy_initLiteralArray(&engine.keyDownEvents);
initLiteralDictionary(&engine.symKeyDownEvents); Toy_initLiteralDictionary(&engine.symKeyDownEvents);
initLiteralArray(&engine.keyUpEvents); Toy_initLiteralArray(&engine.keyUpEvents);
initLiteralDictionary(&engine.symKeyUpEvents); Toy_initLiteralDictionary(&engine.symKeyUpEvents);
//init Toy //init Toy
initInterpreter(&engine.interpreter); Toy_initInterpreter(&engine.interpreter);
injectNativeHook(&engine.interpreter, "engine", hookEngine); Toy_injectNativeHook(&engine.interpreter, "engine", Box_hookEngine);
injectNativeHook(&engine.interpreter, "node", hookNode); Toy_injectNativeHook(&engine.interpreter, "node", Box_hookNode);
injectNativeHook(&engine.interpreter, "input", hookInput); Toy_injectNativeHook(&engine.interpreter, "input", Box_hookInput);
injectNativeHook(&engine.interpreter, "standard", hookStandard); Toy_injectNativeHook(&engine.interpreter, "standard", Toy_hookStandard);
injectNativeHook(&engine.interpreter, "timer", hookTimer); Toy_injectNativeHook(&engine.interpreter, "timer", Toy_hookTimer);
injectNativeHook(&engine.interpreter, "runner", hookRunner); Toy_injectNativeHook(&engine.interpreter, "runner", Toy_hookRunner);
size_t size = 0; size_t size = 0;
char* source = readFile("./assets/scripts/init.toy", &size); char* source = Toy_readFile("./assets/scripts/init.toy", &size);
unsigned char* tb = compileString(source, &size); unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
runInterpreter(&engine.interpreter, tb, size); Toy_runInterpreter(&engine.interpreter, tb, size);
} }
void freeEngine() { void Box_freeEngine() {
//clear existing root node //clear existing root node
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode); Box_freeEngineNode(engine.rootNode);
engine.rootNode = NULL; engine.rootNode = NULL;
} }
freeInterpreter(&engine.interpreter); Toy_freeInterpreter(&engine.interpreter);
//free events //free events
freeLiteralArray(&engine.keyDownEvents); Toy_freeLiteralArray(&engine.keyDownEvents);
freeLiteralDictionary(&engine.symKeyDownEvents); Toy_freeLiteralDictionary(&engine.symKeyDownEvents);
freeLiteralArray(&engine.keyUpEvents); Toy_freeLiteralArray(&engine.keyUpEvents);
freeLiteralDictionary(&engine.symKeyUpEvents); Toy_freeLiteralDictionary(&engine.symKeyUpEvents);
//free SDL //free SDL
SDL_DestroyRenderer(engine.renderer); SDL_DestroyRenderer(engine.renderer);
@@ -97,13 +97,13 @@ void freeEngine() {
static void execEvents() { static void execEvents() {
//clear event lists //clear event lists
if (engine.keyDownEvents.count > 0) { if (engine.keyDownEvents.count > 0) {
freeLiteralArray(&engine.keyDownEvents); Toy_freeLiteralArray(&engine.keyDownEvents);
//NOTE: this is likely memory intensive - a more bespoke linked list designed for this task would be better //NOTE: this is likely memory intensive - a more bespoke linked list designed for this task would be better
//NOTE: alternatively - manual memory-wipes, skipping the free step could be better //NOTE: alternatively - manual memory-wipes, skipping the free step could be better
} }
if (engine.keyUpEvents.count > 0) { if (engine.keyUpEvents.count > 0) {
freeLiteralArray(&engine.keyUpEvents); Toy_freeLiteralArray(&engine.keyUpEvents);
} }
//poll all events //poll all events
@@ -136,16 +136,16 @@ static void execEvents() {
} }
//determine the given keycode //determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) ); Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral)) { if (!Toy_existsLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral)) {
break; break;
} }
//get the event name //get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral); Toy_Literal eventLiteral = Toy_getLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral);
//push to the event list //push to the event list
pushLiteralArray(&engine.keyDownEvents, eventLiteral); Toy_pushLiteralArray(&engine.keyDownEvents, eventLiteral);
} }
break; break;
@@ -156,16 +156,16 @@ static void execEvents() {
} }
//determine the given keycode //determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) ); Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral)) { if (!Toy_existsLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral)) {
break; break;
} }
//get the event name //get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral); Toy_Literal eventLiteral = Toy_getLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral);
//push to the event list //push to the event list
pushLiteralArray(&engine.keyUpEvents, eventLiteral); Toy_pushLiteralArray(&engine.keyUpEvents, eventLiteral);
} }
break; break;
} }
@@ -175,20 +175,20 @@ static void execEvents() {
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
//key down events //key down events
for (int i = 0; i < engine.keyDownEvents.count; i++) { //TODO: could pass in the whole array? for (int i = 0; i < engine.keyDownEvents.count; i++) { //TODO: could pass in the whole array?
LiteralArray args; Toy_LiteralArray args;
initLiteralArray(&args); Toy_initLiteralArray(&args);
pushLiteralArray(&args, engine.keyDownEvents.literals[i]); Toy_pushLiteralArray(&args, engine.keyDownEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyDown", &args); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyDown", &args);
freeLiteralArray(&args); Toy_freeLiteralArray(&args);
} }
//key up events //key up events
for (int i = 0; i < engine.keyUpEvents.count; i++) { for (int i = 0; i < engine.keyUpEvents.count; i++) {
LiteralArray args; Toy_LiteralArray args;
initLiteralArray(&args); Toy_initLiteralArray(&args);
pushLiteralArray(&args, engine.keyUpEvents.literals[i]); Toy_pushLiteralArray(&args, engine.keyUpEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyUp", &args); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyUp", &args);
freeLiteralArray(&args); Toy_freeLiteralArray(&args);
} }
} }
} }
@@ -196,12 +196,12 @@ static void execEvents() {
void execStep() { void execStep() {
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
//steps //steps
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep", NULL); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep", NULL);
} }
} }
//the heart of the engine //the heart of the engine
void execEngine() { void Box_execEngine() {
if (!engine.running) { if (!engine.running) {
fatalError("Can't execute the engine (did you forget to initialize the screen?)"); fatalError("Can't execute the engine (did you forget to initialize the screen?)");
} }
@@ -236,7 +236,7 @@ void execEngine() {
SDL_SetRenderDrawColor(engine.renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later 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_RenderClear(engine.renderer); //NOTE: This line can be disabled later
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw", NULL); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw", NULL);
SDL_RenderPresent(engine.renderer); SDL_RenderPresent(engine.renderer);
} }

View File

@@ -1,26 +1,24 @@
#pragma once #pragma once
#include "core_common.h" #include "box_common.h"
#include "engine_node.h" #include "box_engine_node.h"
#include "interpreter.h"
#include "literal_array.h" #include "toy_interpreter.h"
#include "literal_dictionary.h" #include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
#include "core_common.h"
#include <sys/time.h> #include <sys/time.h>
//the base engine object, which represents the state of the game //the base engine object, which represents the state of the game
typedef struct _engine { typedef struct Box_private_engine {
//engine stuff //engine stuff
EngineNode* rootNode; Box_EngineNode* rootNode;
struct timeval simTime; struct timeval simTime;
struct timeval realTime; struct timeval realTime;
bool running; bool running;
//Toy stuff //Toy stuff
Interpreter interpreter; Toy_Interpreter interpreter;
//SDL stuff //SDL stuff
SDL_Window* window; SDL_Window* window;
@@ -29,18 +27,18 @@ typedef struct _engine {
int screenHeight; int screenHeight;
//input syms mapped to events //input syms mapped to events
LiteralArray keyDownEvents; //list of events that occurred this frame Toy_LiteralArray keyDownEvents; //list of events that occurred this frame
LiteralDictionary symKeyDownEvents; //keysym -> event names Toy_LiteralDictionary symKeyDownEvents; //keysym -> event names
LiteralArray keyUpEvents; //list of events that occurred this frame Toy_LiteralArray keyUpEvents; //list of events that occurred this frame
LiteralDictionary symKeyUpEvents; //keysym -> event names Toy_LiteralDictionary symKeyUpEvents; //keysym -> event names
} Engine; } Box_Engine;
//extern singleton - used by various libraries //extern singleton - used by various libraries
extern Engine engine; extern Box_Engine engine;
//APIs for running the engine in main() //APIs for running the engine in main()
CORE_API void initEngine(); BOX_API void Box_initEngine();
CORE_API void execEngine(); BOX_API void Box_execEngine();
CORE_API void freeEngine(); BOX_API void Box_freeEngine();

View File

@@ -1,22 +1,21 @@
#include "engine_node.h" #include "box_engine_node.h"
#include "box_engine.h"
#include "engine.h" #include "toy_memory.h"
#include "memory.h"
static void freeMemory(void* ptr) { static void freeMemory(void* ptr) {
EngineNode* node = (EngineNode*)ptr; Box_EngineNode* node = (Box_EngineNode*)ptr;
//SDL stuff //SDL stuff
SDL_DestroyTexture(node->texture); SDL_DestroyTexture(node->texture);
//free this node type's memory //free this node type's memory
FREE(EngineNode, ptr); TOY_FREE(Box_EngineNode, ptr);
} }
void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size) { void Box_initEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, void* tb, size_t size) {
//init //init
// node->freeMemory = freeMemory; // node->freeMemory = freeMemory;
node->functions = ALLOCATE(LiteralDictionary, 1); node->functions = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
node->parent = NULL; node->parent = NULL;
node->tag = OPAQUE_TAG_ENGINE_NODE; node->tag = OPAQUE_TAG_ENGINE_NODE;
node->children = NULL; node->children = NULL;
@@ -24,36 +23,36 @@ void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t
node->count = 0; node->count = 0;
node->texture = NULL; node->texture = NULL;
initLiteralDictionary(node->functions); Toy_initLiteralDictionary(node->functions);
//run bytecode //run bytecode
runInterpreter(interpreter, tb, size); Toy_runInterpreter(interpreter, tb, size);
//grab all top-level functions from the dirty interpreter //grab all top-level functions from the dirty interpreter
LiteralDictionary* variablesPtr = &interpreter->scope->variables; Toy_LiteralDictionary* variablesPtr = &interpreter->scope->variables;
for (int i = 0; i < variablesPtr->capacity; i++) { for (int i = 0; i < variablesPtr->capacity; i++) {
//skip empties and tombstones //skip empties and tombstones
if (IS_NULL(variablesPtr->entries[i].key)) { if (TOY_IS_NULL(variablesPtr->entries[i].key)) {
continue; continue;
} }
//if this variable is a function (this outmodes import and export) //if this variable is a function (this outmodes import and export)
_entry* entry = &variablesPtr->entries[i]; Toy_private_entry* entry = &variablesPtr->entries[i];
if (IS_FUNCTION(entry->value)) { if (TOY_IS_FUNCTION(entry->value)) {
//save a copy //save a copy
setLiteralDictionary(node->functions, entry->key, entry->value); Toy_setLiteralDictionary(node->functions, entry->key, entry->value);
} }
} }
} }
void pushEngineNode(EngineNode* node, EngineNode* child) { void Box_pushEngineNode(Box_EngineNode* node, Box_EngineNode* child) {
//push to the array (prune tombstones when expanding/copying) //push to the array (prune tombstones when expanding/copying)
if (node->count + 1 > node->capacity) { if (node->count + 1 > node->capacity) {
int oldCapacity = node->capacity; int oldCapacity = node->capacity;
node->capacity = GROW_CAPACITY(oldCapacity); node->capacity = TOY_GROW_CAPACITY(oldCapacity);
node->children = GROW_ARRAY(EngineNode*, node->children, oldCapacity, node->capacity); node->children = TOY_GROW_ARRAY(Box_EngineNode*, node->children, oldCapacity, node->capacity);
} }
//prune tombstones (experimental) //prune tombstones (experimental)
@@ -77,22 +76,22 @@ void pushEngineNode(EngineNode* node, EngineNode* child) {
child->parent = node; child->parent = node;
} }
void freeEngineNode(EngineNode* node) { void Box_freeEngineNode(Box_EngineNode* node) {
if (node == NULL) { if (node == NULL) {
return; //NO-OP return; //NO-OP
} }
//free and tombstone this node //free and tombstone this node
for (int i = 0; i < node->count; i++) { for (int i = 0; i < node->count; i++) {
freeEngineNode(node->children[i]); Box_freeEngineNode(node->children[i]);
} }
//free the pointer array to the children //free the pointer array to the children
FREE_ARRAY(EngineNode*, node->children, node->capacity); TOY_FREE_ARRAY(Box_EngineNode*, node->children, node->capacity);
if (node->functions != NULL) { if (node->functions != NULL) {
freeLiteralDictionary(node->functions); Toy_freeLiteralDictionary(node->functions);
FREE(LiteralDictionary, node->functions); TOY_FREE(Toy_LiteralDictionary, node->functions);
} }
//free this node's memory //free this node's memory
@@ -100,100 +99,100 @@ void freeEngineNode(EngineNode* node) {
freeMemory(node); freeMemory(node);
} }
Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) { Toy_Literal Box_callEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args) {
Literal ret = TO_NULL_LITERAL; Toy_Literal ret = TOY_TO_NULL_LITERAL;
//if this fn exists //if this fn exists
if (existsLiteralDictionary(node->functions, key)) { if (Toy_existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key); Toy_Literal fn = Toy_getLiteralDictionary(node->functions, key);
Literal n = TO_OPAQUE_LITERAL(node, node->tag); Toy_Literal n = TOY_TO_OPAQUE_LITERAL(node, node->tag);
LiteralArray arguments; Toy_LiteralArray arguments;
LiteralArray returns; Toy_LiteralArray returns;
initLiteralArray(&arguments); Toy_initLiteralArray(&arguments);
initLiteralArray(&returns); Toy_initLiteralArray(&returns);
//feed the arguments in backwards! //feed the arguments in backwards!
if (args) { if (args) {
for (int i = args->count -1; i >= 0; i--) { for (int i = args->count -1; i >= 0; i--) {
pushLiteralArray(&arguments, args->literals[i]); Toy_pushLiteralArray(&arguments, args->literals[i]);
} }
} }
pushLiteralArray(&arguments, n); Toy_pushLiteralArray(&arguments, n);
callLiteralFn(interpreter, fn, &arguments, &returns); Toy_callLiteralFn(interpreter, fn, &arguments, &returns);
ret = popLiteralArray(&returns); ret = Toy_popLiteralArray(&returns);
freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
freeLiteralArray(&returns); Toy_freeLiteralArray(&returns);
freeLiteral(n); Toy_freeLiteral(n);
freeLiteral(fn); Toy_freeLiteral(fn);
} }
return ret; return ret;
} }
Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) { Toy_Literal Box_callEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists //call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(createRefString(fnName)); Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(fnName));
Literal ret = callEngineNodeLiteral(node, interpreter, key, args); Toy_Literal ret = Box_callEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key); Toy_freeLiteral(key);
return ret; return ret;
} }
void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) { void Box_callRecursiveEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args) {
//if this fn exists //if this fn exists
if (existsLiteralDictionary(node->functions, key)) { if (Toy_existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key); Toy_Literal fn = Toy_getLiteralDictionary(node->functions, key);
Literal n = TO_OPAQUE_LITERAL(node, node->tag); Toy_Literal n = TOY_TO_OPAQUE_LITERAL(node, node->tag);
LiteralArray arguments; Toy_LiteralArray arguments;
LiteralArray returns; Toy_LiteralArray returns;
initLiteralArray(&arguments); Toy_initLiteralArray(&arguments);
initLiteralArray(&returns); Toy_initLiteralArray(&returns);
//feed the arguments in backwards! //feed the arguments in backwards!
if (args) { if (args) {
for (int i = args->count -1; i >= 0; i--) { for (int i = args->count -1; i >= 0; i--) {
pushLiteralArray(&arguments, args->literals[i]); Toy_pushLiteralArray(&arguments, args->literals[i]);
} }
} }
pushLiteralArray(&arguments, n); Toy_pushLiteralArray(&arguments, n);
callLiteralFn(interpreter, fn, &arguments, &returns); Toy_callLiteralFn(interpreter, fn, &arguments, &returns);
freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
freeLiteralArray(&returns); Toy_freeLiteralArray(&returns);
freeLiteral(n); Toy_freeLiteral(n);
freeLiteral(fn); Toy_freeLiteral(fn);
} }
//recurse to the (non-tombstone) children //recurse to the (non-tombstone) children
for (int i = 0; i < node->count; i++) { for (int i = 0; i < node->count; i++) {
if (node->children[i] != NULL) { if (node->children[i] != NULL) {
callRecursiveEngineNodeLiteral(node->children[i], interpreter, key, args); Box_callRecursiveEngineNodeLiteral(node->children[i], interpreter, key, args);
} }
} }
} }
void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) { void Box_callRecursiveEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists //call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(createRefString(fnName)); Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(fnName));
callRecursiveEngineNodeLiteral(node, interpreter, key, args); Box_callRecursiveEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key); Toy_freeLiteral(key);
} }
int loadTextureEngineNode(EngineNode* node, char* fname) { int Box_loadTextureEngineNode(Box_EngineNode* node, char* fname) {
SDL_Surface* surface = IMG_Load(fname); SDL_Surface* surface = IMG_Load(fname);
if (surface == NULL) { if (surface == NULL) {
@@ -211,22 +210,22 @@ int loadTextureEngineNode(EngineNode* node, char* fname) {
int w, h; int w, h;
SDL_QueryTexture(node->texture, NULL, NULL, &w, &h); SDL_QueryTexture(node->texture, NULL, NULL, &w, &h);
SDL_Rect r = { 0, 0, w, h }; SDL_Rect r = { 0, 0, w, h };
setRectEngineNode(node, r); Box_setRectEngineNode(node, r);
return 0; return 0;
} }
void freeTextureEngineNode(EngineNode* node) { void Box_freeTextureEngineNode(Box_EngineNode* node) {
if (node->texture != NULL) { if (node->texture != NULL) {
SDL_DestroyTexture(node->texture); SDL_DestroyTexture(node->texture);
node->texture = NULL; node->texture = NULL;
} }
} }
void setRectEngineNode(EngineNode* node, SDL_Rect rect) { void Box_setRectEngineNode(Box_EngineNode* node, SDL_Rect rect) {
node->rect = rect; node->rect = rect;
} }
void drawEngineNode(EngineNode* node, SDL_Rect dest) { void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest) {
SDL_RenderCopy(engine.renderer, node->texture, &node->rect, &dest); SDL_RenderCopy(engine.renderer, node->texture, &node->rect, &dest);
} }

View File

@@ -1,33 +1,33 @@
#pragma once #pragma once
#include "core_common.h" #include "box_common.h"
#include "literal_dictionary.h" #include "toy_literal_dictionary.h"
#include "interpreter.h" #include "toy_interpreter.h"
#define OPAQUE_TAG_ENGINE_NODE 1001 #define OPAQUE_TAG_ENGINE_NODE 1001
//forward declare //forward declare
typedef struct _engineNode EngineNode; typedef struct Box_private_engineNode Box_EngineNode;
// typedef void (*EngineNodeCallback)(void*); // typedef void (*EngineNodeCallback)(void*);
//the node object, which forms a tree //the node object, which forms a tree
typedef struct _engineNode { typedef struct Box_private_engineNode {
//function for releasing memory NOTE: removed, because it's not needed with only 1 node type - I've left them commented out because I might need them soon //function for releasing memory NOTE: removed, because it's not needed with only 1 node type - I've left them commented out because I might need them soon
// EngineNodeCallback freeMemory; // EngineNodeCallback freeMemory;
//toy functions, stored in a dict for flexibility //toy functions, stored in a dict for flexibility
LiteralDictionary* functions; Toy_LiteralDictionary* functions;
//point to the parent //point to the parent
EngineNode* parent; Box_EngineNode* parent;
//my opaque type tag //my opaque type tag
int tag; int tag;
int _unused0; int _unused0;
//use Toy's memory model //use Toy's memory model
EngineNode** children; Box_EngineNode** children;
int capacity; int capacity;
int count; //includes tombstones int count; //includes tombstones
@@ -35,21 +35,21 @@ typedef struct _engineNode {
SDL_Texture* texture; SDL_Texture* texture;
SDL_Rect rect; SDL_Rect rect;
//TODO: depth //TODO: depth
} EngineNode; } Box_EngineNode;
CORE_API void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size); //run bytecode, then grab all top-level function literals BOX_API void Box_initEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, void* tb, size_t size); //run bytecode, then grab all top-level function literals
CORE_API void pushEngineNode(EngineNode* node, EngineNode* child); //push to the array (prune tombstones when expanding/copying) BOX_API void Box_pushEngineNode(Box_EngineNode* node, Box_EngineNode* child); //push to the array (prune tombstones when expanding/copying)
CORE_API void freeEngineNode(EngineNode* node); //free and tombstone this node BOX_API void Box_freeEngineNode(Box_EngineNode* node); //free and tombstone this node
CORE_API Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args); BOX_API Toy_Literal Box_callEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args);
CORE_API Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and only this node, if it exists BOX_API Toy_Literal Box_callEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args); //call "fnName" on this node, and only this node, if it exists
CORE_API void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args); BOX_API void Box_callRecursiveEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args);
CORE_API void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and all children, if it exists BOX_API void Box_callRecursiveEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args); //call "fnName" on this node, and all children, if it exists
CORE_API int loadTextureEngineNode(EngineNode* node, char* fname); BOX_API int Box_loadTextureEngineNode(Box_EngineNode* node, char* fname);
CORE_API void freeTextureEngineNode(EngineNode* node); BOX_API void Box_freeTextureEngineNode(Box_EngineNode* node);
CORE_API void setRectEngineNode(EngineNode* node, SDL_Rect rect); BOX_API void Box_setRectEngineNode(Box_EngineNode* node, SDL_Rect rect);
//TODO: getRect //TODO: getRect
CORE_API void drawEngineNode(EngineNode* node, SDL_Rect dest); BOX_API void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest);

View File

@@ -1,19 +1,21 @@
#include "lib_engine.h" #include "lib_engine.h"
#include "engine.h" #include "box_engine.h"
#include "repl_tools.h"
#include "memory.h" #include "repl_tools.h"
#include "literal_array.h" #include "toy_memory.h"
#include "toy_literal_array.h"
#include "toy_console_colors.h"
//errors here should be fatal //errors here should be fatal
static void fatalError(char* message) { static void fatalError(char* message) {
fprintf(stderr, "%s", message); fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, message);
exit(-1); exit(-1);
} }
//native functions to be called //native functions to be called
static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) { static int nativeInitWindow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (engine.window != NULL) { if (engine.window != NULL) {
fatalError("Can't re-initialize the window\n"); fatalError("Can't re-initialize the window\n");
} }
@@ -23,24 +25,24 @@ static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
} }
//extract the arguments //extract the arguments
Literal fscreen = popLiteralArray(arguments); Toy_Literal fscreen = Toy_popLiteralArray(arguments);
Literal screenHeight = popLiteralArray(arguments); Toy_Literal screenHeight = Toy_popLiteralArray(arguments);
Literal screenWidth = popLiteralArray(arguments); Toy_Literal screenWidth = Toy_popLiteralArray(arguments);
Literal caption = popLiteralArray(arguments); Toy_Literal caption = Toy_popLiteralArray(arguments);
//check argument types //check argument types
if (!IS_STRING(caption) || !IS_INTEGER(screenWidth) || !IS_INTEGER(screenHeight) || !IS_BOOLEAN(fscreen)) { if (!TOY_IS_STRING(caption) || !TOY_IS_INTEGER(screenWidth) || !TOY_IS_INTEGER(screenHeight) || !TOY_IS_BOOLEAN(fscreen)) {
fatalError("Incorrect argument type passed to initEngine\n"); fatalError("Incorrect argument type passed to initEngine\n");
} }
//init the window //init the window
engine.window = SDL_CreateWindow( engine.window = SDL_CreateWindow(
toCString(AS_STRING(caption)), Toy_toCString(TOY_AS_STRING(caption)),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
engine.screenWidth = AS_INTEGER(screenWidth), engine.screenWidth = TOY_AS_INTEGER(screenWidth),
engine.screenHeight = AS_INTEGER(screenHeight), engine.screenHeight = TOY_AS_INTEGER(screenHeight),
IS_TRUTHY(fscreen) ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE TOY_IS_TRUTHY(fscreen) ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE
); );
if (engine.window == NULL) { if (engine.window == NULL) {
@@ -66,81 +68,81 @@ static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
//only run with a window //only run with a window
engine.running = true; engine.running = true;
freeLiteral(caption); Toy_freeLiteral(caption);
freeLiteral(screenWidth); Toy_freeLiteral(screenWidth);
freeLiteral(screenHeight); Toy_freeLiteral(screenHeight);
freeLiteral(fscreen); Toy_freeLiteral(fscreen);
return 0; return 0;
} }
//TODO: perhaps a returns argument would be better? //TODO: perhaps a returns argument would be better?
static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeLoadRootNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to loadRootNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to loadRootNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal fname = popLiteralArray(arguments); Toy_Literal fname = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname; Toy_Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) { if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn); Toy_freeLiteral(fnameIdn);
} }
//check argument types //check argument types
if (!IS_STRING(fname)) { if (!TOY_IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n"); interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n");
freeLiteral(fname); Toy_freeLiteral(fname);
return -1; return -1;
} }
//clear existing root node //clear existing root node
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL); Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode); Box_freeEngineNode(engine.rootNode);
FREE(EngineNode, engine.rootNode); TOY_FREE(Box_EngineNode, engine.rootNode);
engine.rootNode = NULL; engine.rootNode = NULL;
} }
//load the new root node //load the new root node
size_t size = 0; size_t size = 0;
char* source = readFile(toCString(AS_STRING(fname)), &size); char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size);
unsigned char* tb = compileString(source, &size); unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
engine.rootNode = ALLOCATE(EngineNode, 1); engine.rootNode = TOY_ALLOCATE(Box_EngineNode, 1);
//BUGFIX: make an inner-interpreter //BUGFIX: make an inner-interpreter
Interpreter inner; Toy_Interpreter inner;
//init the inner interpreter manually //init the inner interpreter manually
initLiteralArray(&inner.literalCache); Toy_initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL); inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb; inner.bytecode = tb;
inner.length = size; inner.length = size;
inner.count = 0; inner.count = 0;
inner.codeStart = -1; inner.codeStart = -1;
inner.depth = interpreter->depth + 1; inner.depth = interpreter->depth + 1;
inner.panic = false; inner.panic = false;
initLiteralArray(&inner.stack); Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks; inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput); Toy_setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput); Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput); Toy_setInterpreterError(&inner, interpreter->errorOutput);
initEngineNode(engine.rootNode, &inner, tb, size); Box_initEngineNode(engine.rootNode, &inner, tb, size);
//init the new node (and ONLY this node) //init the new node (and ONLY this node)
callEngineNode(engine.rootNode, &engine.interpreter, "onInit", NULL); Box_callEngineNode(engine.rootNode, &engine.interpreter, "onInit", NULL);
//cleanup //cleanup
freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache); Toy_freeLiteralArray(&inner.literalCache);
freeLiteral(fname); Toy_freeLiteral(fname);
return 0; return 0;
} }
@@ -148,10 +150,10 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
char* name; char* name;
NativeFn fn; Toy_NativeFn fn;
} Natives; } Natives;
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) { int Box_hookEngine(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list //build the natives list
Natives natives[] = { Natives natives[] = {
{"initWindow", nativeInitWindow}, {"initWindow", nativeInitWindow},
@@ -160,51 +162,51 @@ int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
}; };
//store the library in an aliased dictionary //store the library in an aliased dictionary
if (!IS_NULL(alias)) { if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken //make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias); Toy_freeLiteral(alias);
return false; return false;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
initLiteralDictionary(dictionary); Toy_initLiteralDictionary(dictionary);
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE; func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name); Toy_freeLiteral(name);
freeLiteral(func); Toy_freeLiteral(func);
} }
//build the type //build the type
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true); Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true); Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true); Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TYPE_PUSH_SUBTYPE(&type, strType); TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TYPE_PUSH_SUBTYPE(&type, fnType); TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope //set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary); Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type); Toy_declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false); Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup //cleanup
freeLiteral(dict); Toy_freeLiteral(dict);
freeLiteral(type); Toy_freeLiteral(type);
return 0; return 0;
} }
//default //default
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn); Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
} }
return 0; return 0;

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "interpreter.h" #include "toy_interpreter.h"
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias); int Box_hookEngine(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

View File

@@ -1,11 +1,11 @@
#include "lib_input.h" #include "lib_input.h"
#include "memory.h" #include "box_common.h"
#include "box_engine.h"
#include "engine.h" #include "toy_memory.h"
#include "core_common.h"
static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* arguments, LiteralDictionary* symKeyEventsPtr, char* fnName) { static int nativeMapInputEventToKey(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments, Toy_LiteralDictionary* symKeyEventsPtr, char* fnName) {
//checks //checks
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to "); interpreter->errorOutput("Incorrect number of arguments passed to ");
@@ -14,26 +14,26 @@ static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* argu
return -1; return -1;
} }
Literal symLiteral = popLiteralArray(arguments); Toy_Literal symLiteral = Toy_popLiteralArray(arguments);
Literal evtLiteral = popLiteralArray(arguments); Toy_Literal evtLiteral = Toy_popLiteralArray(arguments);
Literal evtLiteralIdn = evtLiteral; Toy_Literal evtLiteralIdn = evtLiteral;
if (IS_IDENTIFIER(evtLiteral) && parseIdentifierToValue(interpreter, &evtLiteral)) { if (TOY_IS_IDENTIFIER(evtLiteral) && Toy_parseIdentifierToValue(interpreter, &evtLiteral)) {
freeLiteral(evtLiteralIdn); Toy_freeLiteral(evtLiteralIdn);
} }
Literal symLiteralIdn = symLiteral; Toy_Literal symLiteralIdn = symLiteral;
if (IS_IDENTIFIER(symLiteral) && parseIdentifierToValue(interpreter, &symLiteral)) { if (TOY_IS_IDENTIFIER(symLiteral) && Toy_parseIdentifierToValue(interpreter, &symLiteral)) {
freeLiteral(symLiteralIdn); Toy_freeLiteral(symLiteralIdn);
} }
if (!IS_STRING(symLiteral) || !IS_STRING(evtLiteral)) { if (!TOY_IS_STRING(symLiteral) || !TOY_IS_STRING(evtLiteral)) {
interpreter->errorOutput("Incorrect type of arguments passed to mapInputEventToKey\n"); interpreter->errorOutput("Incorrect type of arguments passed to mapInputEventToKey\n");
return -1; return -1;
} }
//use the keycode for faster lookups //use the keycode for faster lookups
SDL_Keycode keycode = SDL_GetKeyFromName( toCString(AS_STRING(symLiteral)) ); SDL_Keycode keycode = SDL_GetKeyFromName( Toy_toCString(TOY_AS_STRING(symLiteral)) );
if (keycode == SDLK_UNKNOWN) { if (keycode == SDLK_UNKNOWN) {
interpreter->errorOutput("Unknown key found: "); interpreter->errorOutput("Unknown key found: ");
@@ -42,35 +42,35 @@ static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* argu
return -1; return -1;
} }
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)keycode ); Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)keycode );
//save the sym-event pair //save the sym-event pair
setLiteralDictionary(symKeyEventsPtr, keycodeLiteral, evtLiteral); //I could possibly map multiple events to one sym Toy_setLiteralDictionary(symKeyEventsPtr, keycodeLiteral, evtLiteral); //I could possibly map multiple events to one sym
//cleanup //cleanup
freeLiteral(symLiteral); Toy_freeLiteral(symLiteral);
freeLiteral(evtLiteral); Toy_freeLiteral(evtLiteral);
freeLiteral(keycodeLiteral); Toy_freeLiteral(keycodeLiteral);
return 0; return 0;
} }
//dry wrappers //dry wrappers
static int nativeMapInputEventToKeyDown(Interpreter* interpreter, LiteralArray* arguments) { static int nativeMapInputEventToKeyDown(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyDownEvents, "mapInputEventToKeyDown"); return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyDownEvents, "mapInputEventToKeyDown");
} }
static int nativeMapInputEventToKeyUp(Interpreter* interpreter, LiteralArray* arguments) { static int nativeMapInputEventToKeyUp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyUpEvents, "mapInputEventToKeyUp"); return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyUpEvents, "mapInputEventToKeyUp");
} }
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
char* name; char* name;
NativeFn fn; Toy_NativeFn fn;
} Natives; } Natives;
int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) { int Box_hookInput(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list //build the natives list
Natives natives[] = { Natives natives[] = {
{"mapInputEventToKeyDown", nativeMapInputEventToKeyDown}, {"mapInputEventToKeyDown", nativeMapInputEventToKeyDown},
@@ -80,51 +80,51 @@ int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) {
}; };
//store the library in an aliased dictionary //store the library in an aliased dictionary
if (!IS_NULL(alias)) { if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken //make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias); Toy_freeLiteral(alias);
return false; return false;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
initLiteralDictionary(dictionary); Toy_initLiteralDictionary(dictionary);
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE; func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name); Toy_freeLiteral(name);
freeLiteral(func); Toy_freeLiteral(func);
} }
//build the type //build the type
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true); Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true); Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true); Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TYPE_PUSH_SUBTYPE(&type, strType); TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TYPE_PUSH_SUBTYPE(&type, fnType); TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope //set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary); Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type); Toy_declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false); Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup //cleanup
freeLiteral(dict); Toy_freeLiteral(dict);
freeLiteral(type); Toy_freeLiteral(type);
return 0; return 0;
} }
//default //default
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn); Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
} }
return 0; return 0;

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "interpreter.h" #include "toy_interpreter.h"
int hookInput(Interpreter* interpreter, Literal identifier, Literal alias); int Box_hookInput(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

View File

@@ -1,604 +1,604 @@
#include "lib_node.h" #include "lib_node.h"
#include "engine.h" #include "box_engine_node.h"
#include "engine_node.h" #include "box_engine.h"
#include "repl_tools.h"
#include "memory.h" #include "repl_tools.h"
#include "literal_array.h" #include "toy_literal_array.h"
#include "toy_memory.h"
#include <stdlib.h> #include <stdlib.h>
static int nativeLoadNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to loadNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to loadNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal fname = popLiteralArray(arguments); Toy_Literal fname = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname; Toy_Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) { if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn); Toy_freeLiteral(fnameIdn);
} }
//check argument types //check argument types
if (!IS_STRING(fname)) { if (!TOY_IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadNode\n"); interpreter->errorOutput("Incorrect argument type passed to loadNode\n");
freeLiteral(fname); Toy_freeLiteral(fname);
return -1; return -1;
} }
//load the new node //load the new node
size_t size = 0; size_t size = 0;
char* source = readFile(toCString(AS_STRING(fname)), &size); char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size);
unsigned char* tb = compileString(source, &size); unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
EngineNode* node = ALLOCATE(EngineNode, 1); Box_EngineNode* node = TOY_ALLOCATE(Box_EngineNode, 1);
//BUGFIX: make an inner-interpreter //BUGFIX: make an inner-interpreter
Interpreter inner; Toy_Interpreter inner;
//init the inner interpreter manually //init the inner interpreter manually
initLiteralArray(&inner.literalCache); Toy_initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL); inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb; inner.bytecode = tb;
inner.length = size; inner.length = size;
inner.count = 0; inner.count = 0;
inner.codeStart = -1; inner.codeStart = -1;
inner.depth = interpreter->depth + 1; inner.depth = interpreter->depth + 1;
inner.panic = false; inner.panic = false;
initLiteralArray(&inner.stack); Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks; inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput); Toy_setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput); Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput); Toy_setInterpreterError(&inner, interpreter->errorOutput);
initEngineNode(node, &inner, tb, size); Box_initEngineNode(node, &inner, tb, size);
// return the node // return the node
Literal nodeLiteral = TO_OPAQUE_LITERAL(node, node->tag); Toy_Literal nodeLiteral = TOY_TO_OPAQUE_LITERAL(node, node->tag);
pushLiteralArray(&interpreter->stack, nodeLiteral); Toy_pushLiteralArray(&interpreter->stack, nodeLiteral);
//cleanup //cleanup
freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache); Toy_freeLiteralArray(&inner.literalCache);
freeLiteral(fname); Toy_freeLiteral(fname);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return 1; return 1;
} }
static int nativeInitNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeInitNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to initNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to initNode\n");
return -1; return -1;
} }
Literal node = popLiteralArray(arguments); Toy_Literal node = Toy_popLiteralArray(arguments);
Literal nodeIdn = node; Toy_Literal nodeIdn = node;
if (IS_IDENTIFIER(node) && parseIdentifierToValue(interpreter, &node)) { if (TOY_IS_IDENTIFIER(node) && Toy_parseIdentifierToValue(interpreter, &node)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
//check argument types //check argument types
if (!IS_OPAQUE(node)) { if (!TOY_IS_OPAQUE(node)) {
interpreter->errorOutput("Incorrect argument type passed to initNode\n"); interpreter->errorOutput("Incorrect argument type passed to initNode\n");
freeLiteral(node); Toy_freeLiteral(node);
return -1; return -1;
} }
EngineNode* engineNode = AS_OPAQUE(node); Box_EngineNode* engineNode = TOY_AS_OPAQUE(node);
//init the new node (and ONLY this node) //init the new node (and ONLY this node)
callEngineNode(engineNode, &engine.interpreter, "onInit", NULL); Box_callEngineNode(engineNode, &engine.interpreter, "onInit", NULL);
//cleanup //cleanup
freeLiteral(node); Toy_freeLiteral(node);
return 0; return 0;
} }
static int nativeFreeChildNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeFreeChildNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to freeChildNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to freeChildNode\n");
return -1; return -1;
} }
Literal index = popLiteralArray(arguments); Toy_Literal index = Toy_popLiteralArray(arguments);
Literal node = popLiteralArray(arguments); Toy_Literal node = Toy_popLiteralArray(arguments);
Literal nodeIdn = node; //annoying Toy_Literal nodeIdn = node; //annoying
if (IS_IDENTIFIER(node) && parseIdentifierToValue(interpreter, &node)) { if (TOY_IS_IDENTIFIER(node) && Toy_parseIdentifierToValue(interpreter, &node)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
//check argument types //check argument types
if (!IS_OPAQUE(node) || !IS_INTEGER(index)) { if (!TOY_IS_OPAQUE(node) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to freeChildNode\n"); interpreter->errorOutput("Incorrect argument type passed to freeChildNode\n");
freeLiteral(node); Toy_freeLiteral(node);
return -1; return -1;
} }
EngineNode* parentNode = AS_OPAQUE(node); Box_EngineNode* parentNode = TOY_AS_OPAQUE(node);
int idx = AS_INTEGER(index); int idx = TOY_AS_INTEGER(index);
//check bounds //check bounds
if (idx < 0 || idx >= parentNode->count) { if (idx < 0 || idx >= parentNode->count) {
interpreter->errorOutput("Node index out of bounds in freeChildNode\n"); interpreter->errorOutput("Node index out of bounds in freeChildNode\n");
freeLiteral(node); Toy_freeLiteral(node);
freeLiteral(index); Toy_freeLiteral(index);
return -1; return -1;
} }
//get the child node //get the child node
EngineNode* childNode = parentNode->children[idx]; Box_EngineNode* childNode = parentNode->children[idx];
//free the node //free the node
if (childNode != NULL) { if (childNode != NULL) {
callRecursiveEngineNode(childNode, &engine.interpreter, "onFree", NULL); Box_callRecursiveEngineNode(childNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(childNode); Box_freeEngineNode(childNode);
} }
parentNode->children[idx] = NULL; parentNode->children[idx] = NULL;
//cleanup //cleanup
freeLiteral(node); Toy_freeLiteral(node);
freeLiteral(index); Toy_freeLiteral(index);
return 0; return 0;
} }
static int nativePushNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativePushNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to pushNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to pushNode\n");
return -1; return -1;
} }
Literal child = popLiteralArray(arguments); Toy_Literal child = Toy_popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments); Toy_Literal parent = Toy_popLiteralArray(arguments);
Literal parentIdn = parent; Toy_Literal parentIdn = parent;
if (IS_IDENTIFIER(parent) && parseIdentifierToValue(interpreter, &parent)) { if (TOY_IS_IDENTIFIER(parent) && Toy_parseIdentifierToValue(interpreter, &parent)) {
freeLiteral(parentIdn); Toy_freeLiteral(parentIdn);
} }
Literal childIdn = child; Toy_Literal childIdn = child;
if (IS_IDENTIFIER(child) && parseIdentifierToValue(interpreter, &child)) { if (TOY_IS_IDENTIFIER(child) && Toy_parseIdentifierToValue(interpreter, &child)) {
freeLiteral(childIdn); Toy_freeLiteral(childIdn);
} }
if (!IS_OPAQUE(parent) || !IS_OPAQUE(child)) { if (!TOY_IS_OPAQUE(parent) || !TOY_IS_OPAQUE(child)) {
interpreter->errorOutput("Incorrect argument type passed to pushNode\n"); interpreter->errorOutput("Incorrect argument type passed to pushNode\n");
freeLiteral(parent); Toy_freeLiteral(parent);
freeLiteral(child); Toy_freeLiteral(child);
return -1; return -1;
} }
//push the node //push the node
EngineNode* parentNode = AS_OPAQUE(parent); Box_EngineNode* parentNode = TOY_AS_OPAQUE(parent);
EngineNode* childNode = AS_OPAQUE(child); Box_EngineNode* childNode = TOY_AS_OPAQUE(child);
pushEngineNode(parentNode, childNode); Box_pushEngineNode(parentNode, childNode);
//no return value //no return value
freeLiteral(parent); Toy_freeLiteral(parent);
freeLiteral(child); Toy_freeLiteral(child);
return 0; return 0;
} }
static int nativeGetNodeChild(Interpreter* interpreter, LiteralArray* arguments) { static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to getNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to getNode\n");
return -1; return -1;
} }
Literal index = popLiteralArray(arguments); Toy_Literal index = Toy_popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments); Toy_Literal parent = Toy_popLiteralArray(arguments);
Literal parentIdn = parent; Toy_Literal parentIdn = parent;
if (IS_IDENTIFIER(parent) && parseIdentifierToValue(interpreter, &parent)) { if (TOY_IS_IDENTIFIER(parent) && Toy_parseIdentifierToValue(interpreter, &parent)) {
freeLiteral(parentIdn); Toy_freeLiteral(parentIdn);
} }
if (!IS_OPAQUE(parent) || !IS_INTEGER(index)) { if (!TOY_IS_OPAQUE(parent) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to getNode\n"); interpreter->errorOutput("Incorrect argument type passed to getNode\n");
freeLiteral(parent); Toy_freeLiteral(parent);
freeLiteral(index); Toy_freeLiteral(index);
return -1; return -1;
} }
//push the node //push the node
EngineNode* parentNode = AS_OPAQUE(parent); Box_EngineNode* parentNode = TOY_AS_OPAQUE(parent);
int intIndex = AS_INTEGER(index); int intIndex = TOY_AS_INTEGER(index);
if (intIndex < 0 || intIndex >= parentNode->count) { if (intIndex < 0 || intIndex >= parentNode->count) {
interpreter->errorOutput("index out of bounds in getNode\n"); interpreter->errorOutput("index out of bounds in getNode\n");
freeLiteral(parent); Toy_freeLiteral(parent);
freeLiteral(index); Toy_freeLiteral(index);
return -1; return -1;
} }
EngineNode* childNode = parentNode->children[intIndex]; Box_EngineNode* childNode = parentNode->children[intIndex];
Literal child = TO_OPAQUE_LITERAL(childNode, childNode->tag); Toy_Literal child = TOY_TO_OPAQUE_LITERAL(childNode, childNode->tag);
pushLiteralArray(&interpreter->stack, child); Toy_pushLiteralArray(&interpreter->stack, child);
//no return value //no return value
freeLiteral(parent); Toy_freeLiteral(parent);
freeLiteral(child); Toy_freeLiteral(child);
freeLiteral(index); Toy_freeLiteral(index);
return 1; return 1;
} }
static int nativeGetNodeParent(Interpreter* interpreter, LiteralArray* arguments) { static int nativeGetNodeParent(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to getNodeParent\n"); interpreter->errorOutput("Incorrect number of arguments passed to getNodeParent\n");
return -1; return -1;
} }
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
if (!IS_OPAQUE(nodeLiteral)) { if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeParent\n"); interpreter->errorOutput("Incorrect argument type passed to getNodeParent\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return -1; return -1;
} }
//push the node //push the node
EngineNode* node = AS_OPAQUE(nodeLiteral); Box_EngineNode* node = TOY_AS_OPAQUE(nodeLiteral);
EngineNode* parent = node->parent; Box_EngineNode* parent = node->parent;
Literal parentLiteral = TO_NULL_LITERAL; Toy_Literal parentLiteral = TOY_TO_NULL_LITERAL;
if (parent != NULL) { if (parent != NULL) {
parentLiteral = TO_OPAQUE_LITERAL(parent, parent->tag); parentLiteral = TOY_TO_OPAQUE_LITERAL(parent, parent->tag);
} }
pushLiteralArray(&interpreter->stack, parentLiteral); Toy_pushLiteralArray(&interpreter->stack, parentLiteral);
//cleanup //cleanup
freeLiteral(parentLiteral); Toy_freeLiteral(parentLiteral);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return 1; return 1;
} }
static int nativeLoadTexture(Interpreter* interpreter, LiteralArray* arguments) { static int nativeLoadTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to loadTextureEngineNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to loadTextureEngineNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal fname = popLiteralArray(arguments); Toy_Literal fname = Toy_popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname; Toy_Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) { if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn); Toy_freeLiteral(fnameIdn);
} }
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
//check argument types //check argument types
if (!IS_STRING(fname) || !IS_OPAQUE(nodeLiteral)) { if (!TOY_IS_STRING(fname) || !TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to loadTextureEngineNode\n"); interpreter->errorOutput("Incorrect argument type passed to loadTextureEngineNode\n");
freeLiteral(fname); Toy_freeLiteral(fname);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return -1; return -1;
} }
//actually load TODO: number the opaques, and check the numbers //actually load TODO: number the opaques, and check the numbers
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral); Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
if (node->texture != NULL) { if (node->texture != NULL) {
freeTextureEngineNode(node); Box_freeTextureEngineNode(node);
} }
if (loadTextureEngineNode(node, toCString(AS_STRING(fname))) != 0) { if (Box_loadTextureEngineNode(node, Toy_toCString(TOY_AS_STRING(fname))) != 0) {
interpreter->errorOutput("Failed to load the texture into the EngineNode\n"); interpreter->errorOutput("Failed to load the texture into the EngineNode\n");
freeLiteral(fname); Toy_freeLiteral(fname);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return -1; return -1;
} }
//cleanup //cleanup
freeLiteral(fname); Toy_freeLiteral(fname);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return 0; return 0;
} }
static int nativeFreeTexture(Interpreter* interpreter, LiteralArray* arguments) { static int nativeFreeTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to freeTextureEngineNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to freeTextureEngineNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
//check argument types //check argument types
if (!IS_OPAQUE(nodeLiteral)) { if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to freeTextureEngineNode\n"); interpreter->errorOutput("Incorrect argument type passed to freeTextureEngineNode\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return -1; return -1;
} }
//actually load TODO: number the opaques, and check the numbers //actually load TODO: number the opaques, and check the numbers
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral); Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
if (node->texture != NULL) { if (node->texture != NULL) {
freeTextureEngineNode(node); Box_freeTextureEngineNode(node);
} }
//cleanup //cleanup
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return 0; return 0;
} }
static int nativeSetRect(Interpreter* interpreter, LiteralArray* arguments) { static int nativeSetRect(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 5) { if (arguments->count != 5) {
interpreter->errorOutput("Incorrect number of arguments passed to setRectEngineNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to setRectEngineNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal h = popLiteralArray(arguments); Toy_Literal h = Toy_popLiteralArray(arguments);
Literal w = popLiteralArray(arguments); Toy_Literal w = Toy_popLiteralArray(arguments);
Literal y = popLiteralArray(arguments); Toy_Literal y = Toy_popLiteralArray(arguments);
Literal x = popLiteralArray(arguments); Toy_Literal x = Toy_popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
Literal xi = x; Toy_Literal xi = x;
if (IS_IDENTIFIER(x) && parseIdentifierToValue(interpreter, &x)) { if (TOY_IS_IDENTIFIER(x) && Toy_parseIdentifierToValue(interpreter, &x)) {
freeLiteral(xi); Toy_freeLiteral(xi);
} }
Literal yi = y; Toy_Literal yi = y;
if (IS_IDENTIFIER(y) && parseIdentifierToValue(interpreter, &y)) { if (TOY_IS_IDENTIFIER(y) && Toy_parseIdentifierToValue(interpreter, &y)) {
freeLiteral(yi); Toy_freeLiteral(yi);
} }
Literal wi = w; Toy_Literal wi = w;
if (IS_IDENTIFIER(w) && parseIdentifierToValue(interpreter, &w)) { if (TOY_IS_IDENTIFIER(w) && Toy_parseIdentifierToValue(interpreter, &w)) {
freeLiteral(wi); Toy_freeLiteral(wi);
} }
Literal hi = h; Toy_Literal hi = h;
if (IS_IDENTIFIER(h) && parseIdentifierToValue(interpreter, &h)) { if (TOY_IS_IDENTIFIER(h) && Toy_parseIdentifierToValue(interpreter, &h)) {
freeLiteral(hi); Toy_freeLiteral(hi);
} }
//check argument types //check argument types
if (!IS_OPAQUE(nodeLiteral) || !IS_INTEGER(x) || !IS_INTEGER(y) || !IS_INTEGER(w) || !IS_INTEGER(h)) { if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_INTEGER(x) || !TOY_IS_INTEGER(y) || !TOY_IS_INTEGER(w) || !TOY_IS_INTEGER(h)) {
interpreter->errorOutput("Incorrect argument type passed to setRectEngineNode\n"); interpreter->errorOutput("Incorrect argument type passed to setRectEngineNode\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(x); Toy_freeLiteral(x);
freeLiteral(y); Toy_freeLiteral(y);
freeLiteral(w); Toy_freeLiteral(w);
freeLiteral(h); Toy_freeLiteral(h);
return -1; return -1;
} }
//actually set //actually set
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral); Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
SDL_Rect r = {AS_INTEGER(x), AS_INTEGER(y), AS_INTEGER(w), AS_INTEGER(h)}; SDL_Rect r = {TOY_AS_INTEGER(x), TOY_AS_INTEGER(y), TOY_AS_INTEGER(w), TOY_AS_INTEGER(h)};
setRectEngineNode(node, r); Box_setRectEngineNode(node, r);
//cleanup //cleanup
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(x); Toy_freeLiteral(x);
freeLiteral(y); Toy_freeLiteral(y);
freeLiteral(w); Toy_freeLiteral(w);
freeLiteral(h); Toy_freeLiteral(h);
return 0; return 0;
} }
//TODO: get x, y, w, h //TODO: get x, y, w, h
static int nativeDrawNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 3 && arguments->count != 5) { if (arguments->count != 3 && arguments->count != 5) {
interpreter->errorOutput("Incorrect number of arguments passed to drawEngineNode\n"); interpreter->errorOutput("Incorrect number of arguments passed to drawEngineNode\n");
return -1; return -1;
} }
//extract the arguments //extract the arguments
Literal w = TO_NULL_LITERAL, h = TO_NULL_LITERAL; Toy_Literal w = TOY_TO_NULL_LITERAL, h = TOY_TO_NULL_LITERAL;
if (arguments->count == 5) { if (arguments->count == 5) {
h = popLiteralArray(arguments); h = Toy_popLiteralArray(arguments);
w = popLiteralArray(arguments); w = Toy_popLiteralArray(arguments);
} }
Literal y = popLiteralArray(arguments); Toy_Literal y = Toy_popLiteralArray(arguments);
Literal x = popLiteralArray(arguments); Toy_Literal x = Toy_popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
Literal xi = x; Toy_Literal xi = x;
if (IS_IDENTIFIER(x) && parseIdentifierToValue(interpreter, &x)) { if (TOY_IS_IDENTIFIER(x) && Toy_parseIdentifierToValue(interpreter, &x)) {
freeLiteral(xi); Toy_freeLiteral(xi);
} }
Literal yi = y; Toy_Literal yi = y;
if (IS_IDENTIFIER(y) && parseIdentifierToValue(interpreter, &y)) { if (TOY_IS_IDENTIFIER(y) && Toy_parseIdentifierToValue(interpreter, &y)) {
freeLiteral(yi); Toy_freeLiteral(yi);
} }
Literal wi = w; Toy_Literal wi = w;
if (IS_IDENTIFIER(w) && parseIdentifierToValue(interpreter, &w)) { if (TOY_IS_IDENTIFIER(w) && Toy_parseIdentifierToValue(interpreter, &w)) {
freeLiteral(wi); Toy_freeLiteral(wi);
} }
Literal hi = h; Toy_Literal hi = h;
if (IS_IDENTIFIER(h) && parseIdentifierToValue(interpreter, &h)) { if (TOY_IS_IDENTIFIER(h) && Toy_parseIdentifierToValue(interpreter, &h)) {
freeLiteral(hi); Toy_freeLiteral(hi);
} }
//check argument types //check argument types
if (!IS_OPAQUE(nodeLiteral) || !IS_INTEGER(x) || !IS_INTEGER(y) || (!IS_INTEGER(w) && !IS_NULL(w)) || (!IS_INTEGER(h) && !IS_NULL(h))) { if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_INTEGER(x) || !TOY_IS_INTEGER(y) || (!TOY_IS_INTEGER(w) && !TOY_IS_NULL(w)) || (!TOY_IS_INTEGER(h) && !TOY_IS_NULL(h))) {
interpreter->errorOutput("Incorrect argument type passed to drawEngineNode\n"); interpreter->errorOutput("Incorrect argument type passed to drawEngineNode\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(x); Toy_freeLiteral(x);
freeLiteral(y); Toy_freeLiteral(y);
freeLiteral(w); Toy_freeLiteral(w);
freeLiteral(h); Toy_freeLiteral(h);
return -1; return -1;
} }
//actually render //actually render
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral); Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
SDL_Rect r = {AS_INTEGER(x), AS_INTEGER(y), 0, 0}; SDL_Rect r = {TOY_AS_INTEGER(x), TOY_AS_INTEGER(y), 0, 0};
if (IS_INTEGER(w) && IS_INTEGER(h)) { if (TOY_IS_INTEGER(w) && TOY_IS_INTEGER(h)) {
r.w = AS_INTEGER(w); r.w = TOY_AS_INTEGER(w);
r.h = AS_INTEGER(h); r.h = TOY_AS_INTEGER(h);
} }
else { else {
r.w = node->rect.w; r.w = node->rect.w;
r.h = node->rect.h; r.h = node->rect.h;
} }
drawEngineNode(node, r); Box_drawEngineNode(node, r);
//cleanup //cleanup
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(x); Toy_freeLiteral(x);
freeLiteral(y); Toy_freeLiteral(y);
freeLiteral(w); Toy_freeLiteral(w);
freeLiteral(h); Toy_freeLiteral(h);
return 0; return 0;
} }
static int nativeGetNodeTag(Interpreter* interpreter, LiteralArray* arguments) { static int nativeGetNodeTag(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to getNodeTag\n"); interpreter->errorOutput("Incorrect number of arguments passed to getNodeTag\n");
return -1; return -1;
} }
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
if (!IS_OPAQUE(nodeLiteral)) { if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeTag\n"); interpreter->errorOutput("Incorrect argument type passed to getNodeTag\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
return -1; return -1;
} }
//push the tag //push the tag
Literal tagLiteral = TO_INTEGER_LITERAL( ((EngineNode*)AS_OPAQUE(nodeLiteral))->tag ); Toy_Literal tagLiteral = TOY_TO_INTEGER_LITERAL( ((Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral))->tag );
pushLiteralArray(&interpreter->stack, tagLiteral); Toy_pushLiteralArray(&interpreter->stack, tagLiteral);
//cleanup //cleanup
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(tagLiteral); Toy_freeLiteral(tagLiteral);
return 1; return 1;
} }
static int nativeCallNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count < 2) { if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments passed to callEngineNode\n"); interpreter->errorOutput("Too few arguments passed to callEngineNode\n");
return -1; return -1;
} }
LiteralArray extraArgs; Toy_LiteralArray extraArgs;
initLiteralArray(&extraArgs); Toy_initLiteralArray(&extraArgs);
LiteralArray flippedExtraArgs; Toy_LiteralArray flippedExtraArgs;
initLiteralArray(&flippedExtraArgs); Toy_initLiteralArray(&flippedExtraArgs);
//extract the extra arg values //extract the extra arg values
while (arguments->count > 2) { while (arguments->count > 2) {
Literal tmp = popLiteralArray(arguments); Toy_Literal tmp = Toy_popLiteralArray(arguments);
Literal idn = tmp; //there's almost certainly a better way of doing all of this stuff Toy_Literal idn = tmp; //there's almost certainly a better way of doing all of this stuff
if (IS_IDENTIFIER(tmp) && parseIdentifierToValue(interpreter, &tmp)) { if (TOY_IS_IDENTIFIER(tmp) && Toy_parseIdentifierToValue(interpreter, &tmp)) {
freeLiteral(idn); Toy_freeLiteral(idn);
} }
pushLiteralArray(&flippedExtraArgs, tmp); Toy_pushLiteralArray(&flippedExtraArgs, tmp);
freeLiteral(tmp); Toy_freeLiteral(tmp);
} }
//correct the order //correct the order
while (flippedExtraArgs.count) { while (flippedExtraArgs.count) {
Literal tmp = popLiteralArray(&flippedExtraArgs); Toy_Literal tmp = Toy_popLiteralArray(&flippedExtraArgs);
pushLiteralArray(&extraArgs, tmp); Toy_pushLiteralArray(&extraArgs, tmp);
freeLiteral(tmp); Toy_freeLiteral(tmp);
} }
freeLiteralArray(&flippedExtraArgs); Toy_freeLiteralArray(&flippedExtraArgs);
//back on track //back on track
Literal fnName = popLiteralArray(arguments); Toy_Literal fnName = Toy_popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral; Toy_Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) { if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn); Toy_freeLiteral(nodeIdn);
} }
Literal fnNameIdn = fnName; Toy_Literal fnNameIdn = fnName;
if (IS_IDENTIFIER(fnName) && parseIdentifierToValue(interpreter, &fnName)) { if (TOY_IS_IDENTIFIER(fnName) && Toy_parseIdentifierToValue(interpreter, &fnName)) {
freeLiteral(fnNameIdn); Toy_freeLiteral(fnNameIdn);
} }
if (!IS_OPAQUE(nodeLiteral) || !IS_STRING(fnName)) { if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_STRING(fnName)) {
interpreter->errorOutput("Incorrect argument type passed to callEngineNode\n"); interpreter->errorOutput("Incorrect argument type passed to callEngineNode\n");
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(fnName); Toy_freeLiteral(fnName);
return -1; return -1;
} }
//allow refstring to do it's magic //allow refstring to do it's magic
Literal fnNameIdentifier = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(fnName))); Toy_Literal fnNameIdentifier = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(fnName)));
//call the function //call the function
Literal result = callEngineNodeLiteral(AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier, &extraArgs); Toy_Literal result = Box_callEngineNodeLiteral(TOY_AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier, &extraArgs);
pushLiteralArray(&interpreter->stack, result); Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup //cleanup
freeLiteralArray(&extraArgs); Toy_freeLiteralArray(&extraArgs);
freeLiteral(nodeLiteral); Toy_freeLiteral(nodeLiteral);
freeLiteral(fnName); Toy_freeLiteral(fnName);
freeLiteral(result); Toy_freeLiteral(result);
return 1; return 1;
} }
@@ -606,10 +606,10 @@ static int nativeCallNode(Interpreter* interpreter, LiteralArray* arguments) {
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
char* name; char* name;
NativeFn fn; Toy_NativeFn fn;
} Natives; } Natives;
int hookNode(Interpreter* interpreter, Literal identifier, Literal alias) { int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list //build the natives list
Natives natives[] = { Natives natives[] = {
{"loadNode", nativeLoadNode}, {"loadNode", nativeLoadNode},
@@ -628,51 +628,51 @@ int hookNode(Interpreter* interpreter, Literal identifier, Literal alias) {
}; };
//store the library in an aliased dictionary //store the library in an aliased dictionary
if (!IS_NULL(alias)) { if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken //make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias); Toy_freeLiteral(alias);
return false; return false;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
initLiteralDictionary(dictionary); Toy_initLiteralDictionary(dictionary);
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE; func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name); Toy_freeLiteral(name);
freeLiteral(func); Toy_freeLiteral(func);
} }
//build the type //build the type
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true); Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true); Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true); Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TYPE_PUSH_SUBTYPE(&type, strType); TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TYPE_PUSH_SUBTYPE(&type, fnType); TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope //set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary); Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type); Toy_declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false); Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup //cleanup
freeLiteral(dict); Toy_freeLiteral(dict);
freeLiteral(type); Toy_freeLiteral(type);
return 0; return 0;
} }
//default //default
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn); Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
} }
return 0; return 0;

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "interpreter.h" #include "toy_interpreter.h"
int hookNode(Interpreter* interpreter, Literal identifier, Literal alias); int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

613
box/lib_runner.c Normal file
View File

@@ -0,0 +1,613 @@
#include "lib_runner.h"
#include "toy_memory.h"
#include "toy_interpreter.h"
#include "repl_tools.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct Toy_Runner {
Toy_Interpreter interpreter;
unsigned char* bytecode;
size_t size;
bool dirty;
} Toy_Runner;
//Toy native functions
static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) {
interpreter->errorOutput("Bad script file extension (expected .toy)\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load and compile the bytecode
size_t fileSize = 0;
char* source = Toy_readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
return -1;
}
unsigned char* bytecode = Toy_compileString(source, &fileSize);
free((void*)source);
if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load the bytecode
size_t fileSize = 0;
unsigned char* bytecode = (unsigned char*)Toy_readFile(filePath, &fileSize);
if (!bytecode) {
interpreter->errorOutput("Failed to load bytecode file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
if (runner->dirty) {
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
unsigned char* bytecodeCopy = TOY_ALLOCATE(unsigned char, runner->size);
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
Toy_runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
runner->dirty = true;
//cleanup
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
return -1;
}
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal result = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &result);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return 1;
}
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
return -1;
}
//get the rest args
Toy_LiteralArray tmp;
Toy_initLiteralArray(&tmp);
while (arguments->count > 2) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&tmp, lit);
Toy_freeLiteral(lit);
}
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
Toy_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
}
Toy_freeLiteralArray(&tmp);
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal fn = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &fn);
if (!TOY_IS_FUNCTION(fn)) {
interpreter->errorOutput("Can't run a non-function literal\n");
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
}
//call
Toy_LiteralArray resultArray;
Toy_initLiteralArray(&resultArray);
Toy_callLiteralFn(interpreter, fn, &rest, &resultArray);
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (resultArray.count > 0) {
result = Toy_popLiteralArray(&resultArray);
}
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteralArray(&resultArray);
Toy_freeLiteral(result);
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return 1;
}
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//reset
if (!runner->dirty) {
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
Toy_resetInterpreter(&runner->interpreter);
runner->dirty = false;
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//clear out the runner object
runner->interpreter.hooks = NULL;
Toy_freeInterpreter(&runner->interpreter);
TOY_FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
TOY_FREE(Toy_Runner, runner);
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
Toy_Literal result = TOY_TO_BOOLEAN_LITERAL(runner->dirty);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(runnerLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
//file system API
static Toy_LiteralDictionary Toy_driveDictionary;
void Toy_initDriveDictionary() {
Toy_initLiteralDictionary(&Toy_driveDictionary);
}
void Toy_freeDriveDictionary() {
Toy_freeLiteralDictionary(&Toy_driveDictionary);
}
Toy_LiteralDictionary* Toy_getDriveDictionary() {
return &Toy_driveDictionary;
}

12
box/lib_runner.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
//file system API - these need to be set by the host
void Toy_initDriveDictionary();
void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100

95
box/lib_standard.c Normal file
View File

@@ -0,0 +1,95 @@
#include "lib_standard.h"
#include "toy_memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Toy_Interpreter* interpreter, Toy_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
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
//push to the stack
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
return 1;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"clock", nativeClock},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}

6
box/lib_standard.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

412
box/lib_timer.c Normal file
View File

@@ -0,0 +1,412 @@
#include "lib_timer.h"
#include "toy_memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
//normallize
if (x->tv_usec > 999999) {
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}
if (y->tv_usec > 999999) {
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}
//calc
result->tv_sec = x->tv_sec - y->tv_sec;
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0) {
if (result->tv_sec != 0) { //only works far from 0
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
}
return result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0);
}
//god damn it
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
struct timeval* d = TOY_ALLOCATE(struct timeval, 1);
//I gave up, copied from SO
timeval_subtract(d, rhs, lhs);
return d;
}
//callbacks
static int nativeStartTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
gettimeofday(timeinfo, NULL);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
return 1;
}
static int nativeStopTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval timerStop;
gettimeofday(&timerStop, NULL);
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timerStart = TOY_AS_OPAQUE(timeLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(timerStart, &timerStop);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeCreateTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
return -1;
}
//get the args
Toy_Literal microsecondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteralIdn = secondLiteral;
if (TOY_IS_IDENTIFIER(secondLiteral) && Toy_parseIdentifierToValue(interpreter, &secondLiteral)) {
Toy_freeLiteral(secondLiteralIdn);
}
Toy_Literal microsecondLiteralIdn = microsecondLiteral;
if (TOY_IS_IDENTIFIER(microsecondLiteral) && Toy_parseIdentifierToValue(interpreter, &microsecondLiteral)) {
Toy_freeLiteral(microsecondLiteralIdn);
}
if (!TOY_IS_INTEGER(secondLiteral) || !TOY_IS_INTEGER(microsecondLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
if (TOY_AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || TOY_AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (TOY_AS_INTEGER(secondLiteral) != 0 && TOY_AS_INTEGER(microsecondLiteral) < 0) ) {
interpreter->errorOutput("Microseconds out of range in createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
//get the timeinfo from toy
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
timeinfo->tv_sec = TOY_AS_INTEGER(secondLiteral);
timeinfo->tv_usec = TOY_AS_INTEGER(microsecondLiteral);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return 1;
}
static int nativeGetTimerSeconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_sec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeGetTimerMicroseconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_usec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeCompareTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
return -1;
}
//unwrap the opaque literals
Toy_Literal rhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteralIdn = lhsLiteral;
if (TOY_IS_IDENTIFIER(lhsLiteral) && Toy_parseIdentifierToValue(interpreter, &lhsLiteral)) {
Toy_freeLiteral(lhsLiteralIdn);
}
Toy_Literal rhsLiteralIdn = rhsLiteral;
if (TOY_IS_IDENTIFIER(rhsLiteral) && Toy_parseIdentifierToValue(interpreter, &rhsLiteral)) {
Toy_freeLiteral(rhsLiteralIdn);
}
if (!TOY_IS_OPAQUE(lhsLiteral) || !TOY_IS_OPAQUE(rhsLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
return -1;
}
struct timeval* lhsTimer = TOY_AS_OPAQUE(lhsLiteral);
struct timeval* rhsTimer = TOY_AS_OPAQUE(rhsLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(lhsTimer, rhsTimer);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeTimerToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the string literal
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
char buffer[128];
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
else { //normal case
char buffer[128];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(resultLiteral);
return 1;
}
static int nativeDestroyTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
TOY_FREE(struct timeval, timer);
Toy_freeLiteral(timeLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"startTimer", nativeStartTimer},
{"_stopTimer", nativeStopTimer},
{"createTimer", nativeCreateTimer},
{"_getTimerSeconds", nativeGetTimerSeconds},
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
{"_compareTimer", nativeCompareTimer},
{"_timerToString", nativeTimerToString},
{"_destroyTimer", nativeDestroyTimer},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}

6
box/lib_timer.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

146
box/repl_tools.c Normal file
View File

@@ -0,0 +1,146 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
#include <stdio.h>
#include <stdlib.h>
//IO functions
char* Toy_readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
fseek(file, 0L, SEEK_END);
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
if (buffer == NULL) {
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
if (bytesRead < *fileSize) {
fprintf(stderr, TOY_CC_ERROR "Could not read file \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
fclose(file);
return buffer;
}
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
int written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
fclose(file);
return 0;
}
//repl functions
unsigned char* Toy_compileString(char* source, size_t* size) {
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
//run the parser until the end of the source
Toy_ASTNode* node = Toy_scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == TOY_AST_NODE_ERROR) {
Toy_freeASTNode(node);
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
return NULL;
}
Toy_writeCompiler(&compiler, node);
Toy_freeASTNode(node);
node = Toy_scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
//cleanup
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
//no lexer to clean up
//finally
return tb;
}
void Toy_runBinary(unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_freeInterpreter(&interpreter);
}
void Toy_runBinaryFile(char* fname) {
size_t size = 0; //not used
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
//interpreter takes ownership of the binary data
}
void Toy_runSource(char* source) {
size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
}
void Toy_runSourceFile(char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
Toy_runSource(source);
free((void*)source);
}

14
box/repl_tools.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "toy_common.h"
char* Toy_readFile(char* path, size_t* fileSize);
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
unsigned char* Toy_compileString(char* source, size_t* size);
void Toy_runBinary(unsigned char* tb, size_t size);
void Toy_runBinaryFile(char* fname);
void Toy_runSource(char* source);
void Toy_runSourceFile(char* fname);

View File

@@ -1,33 +1,33 @@
//moved here for android shenanigans //moved here for android shenanigans
#define SDL_MAIN_HANDLED #define SDL_MAIN_HANDLED
#include "engine.h" #include "box_engine.h"
//the runner library needs a little more setup since it accesses the disk //the runner library needs a little more setup since it accesses the disk
#include "lib_runner.h" #include "lib_runner.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
//the drive system uses a LiteralDictionary, which must be initialized with this //the drive system uses a LiteralDictionary, which must be initialized with this
initDriveDictionary(); Toy_initDriveDictionary();
//create a pair of literals, the first for the drive name, the second for the path //create a pair of literals, the first for the drive name, the second for the path
Literal driveLiteral = TO_STRING_LITERAL(createRefString("scripts")); Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Literal pathLiteral = TO_STRING_LITERAL(createRefString("assets/scripts")); Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("assets/scripts"));
//set these within the drive dictionary //set these within the drive dictionary
setLiteralDictionary(getDriveDictionary(), driveLiteral, pathLiteral); Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
//these literals are no longer needed //these literals are no longer needed
freeLiteral(driveLiteral); Toy_freeLiteral(driveLiteral);
freeLiteral(pathLiteral); Toy_freeLiteral(pathLiteral);
//run the rest of your program //run the rest of your program
initEngine(); Box_initEngine();
execEngine(); Box_execEngine();
freeEngine(); Box_freeEngine();
//clean up the drive dictionary when you're done //clean up the drive dictionary when you're done
freeDriveDictionary(); Toy_freeDriveDictionary();
return 0; return 0;
} }