Added some node functionality to scripts

This commit is contained in:
2022-10-07 10:25:09 +01:00
parent ecaf554b9a
commit 6b5cd7f580
5 changed files with 306 additions and 19 deletions

11
assets/scripts/child.toy Normal file
View File

@@ -0,0 +1,11 @@
fn onInit(node: opaque) {
print "child.toy:onInit() called";
}
fn onStep(node: opaque) {
print "child.toy:onStep()";
}
fn onFree(node: opaque) {
print "child.toy:onFree() called";
}

View File

@@ -1,14 +1,34 @@
import standard; import standard;
import engine;
//root node can load the whole scene, and essentially act as the scene object fn makeChild(parent: opaque, fname: string, init: bool) {
fn onInit() { var child: opaque = loadNode(fname);
print "root.toy:onInit() called";
if (init) {
initNode(child);
} }
fn onStep() { pushNode(parent, child);
}
//root node can load the whole scene, and essentially act as the scene object
fn onInit(node: opaque) {
print "root.toy:onInit() called";
//make a child
makeChild(node, "assets/scripts/child.toy", true); //indicate whether to call "init" on the new node or not
makeChild(node, "assets/scripts/child.toy", false);
makeChild(node, "assets/scripts/child.toy", false);
//actually, grab that first node and free it
var o: opaque = getNode(node, 0);
freeNode(o);
}
fn onStep(node: opaque) {
print clock(); print clock();
} }
fn onFree() { fn onFree(node: opaque) {
print "root.toy:onFree() called"; print "root.toy:onFree() called";
} }

View File

@@ -90,14 +90,21 @@ static void callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Li
//if this fn exists //if this fn exists
if (existsLiteralDictionary(node->functions, key)) { if (existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key); Literal fn = getLiteralDictionary(node->functions, key);
Literal n = TO_OPAQUE_LITERAL(node, -1);
LiteralArray dummyArray; LiteralArray arguments;
initLiteralArray(&dummyArray); LiteralArray returns;
initLiteralArray(&arguments);
initLiteralArray(&returns);
callLiteralFn(interpreter, fn, &dummyArray, &dummyArray); pushLiteralArray(&arguments, n);
freeLiteralArray(&dummyArray); callLiteralFn(interpreter, fn, &arguments, &returns);
freeLiteralArray(&arguments);
freeLiteralArray(&returns);
freeLiteral(n);
freeLiteral(fn); freeLiteral(fn);
} }

View File

@@ -14,6 +14,7 @@ typedef struct _engineNode {
EngineNode* children; EngineNode* children;
int capacity; int capacity;
int count; //includes tombstones int count; //includes tombstones
//TODO: add "liveCount"
//toy functions, stored in a dict for flexibility //toy functions, stored in a dict for flexibility
LiteralDictionary* functions; LiteralDictionary* functions;

View File

@@ -74,6 +74,7 @@ static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
return 0; return 0;
} }
//TODO: perhaps a returns argument would be better?
static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments) { static int nativeLoadRootNode(Interpreter* interpreter, 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");
@@ -83,6 +84,11 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
//extract the arguments //extract the arguments
Literal fname = popLiteralArray(arguments); Literal fname = popLiteralArray(arguments);
Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn);
}
//check argument types //check argument types
if (!IS_STRING(fname)) { if (!IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n"); interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n");
@@ -108,28 +114,265 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
engine.rootNode = ALLOCATE(EngineNode, 1); engine.rootNode = ALLOCATE(EngineNode, 1);
//BUGFIX //BUGFIX: make an inner-interpreter
unsigned char* originalTb = engine.interpreter.bytecode; Interpreter inner;
size_t originalSize = engine.interpreter.length;
int originalCount = engine.interpreter.count;
int originalCodeStart = engine.interpreter.codeStart;
initEngineNode(engine.rootNode, &engine.interpreter, tb, size); //init the inner interpreter manually
initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL);
inner.bytecode = tb;
inner.length = size;
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
inner.panic = false;
initLiteralArray(&inner.stack);
inner.exports = interpreter->exports;
inner.exportTypes = interpreter->exportTypes;
inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput);
engine.interpreter.bytecode = originalTb; initEngineNode(engine.rootNode, &inner, tb, size);
engine.interpreter.length = originalSize;
engine.interpreter.count = originalCount;
engine.interpreter.codeStart = originalCodeStart;
//init the new node //init the new node
callEngineNode(engine.rootNode, &engine.interpreter, "onInit"); callEngineNode(engine.rootNode, &engine.interpreter, "onInit");
//cleanup //cleanup
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
freeLiteral(fname); freeLiteral(fname);
return 0; return 0;
} }
static int nativeLoadNode(Interpreter* interpreter, LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to loadNode\n");
return -1;
}
//extract the arguments
Literal fname = popLiteralArray(arguments);
Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn);
}
//check argument types
if (!IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadNode\n");
freeLiteral(fname);
return -1;
}
//load the new node
size_t size = 0;
char* source = readFile(AS_STRING(fname), &size);
unsigned char* tb = compileString(source, &size);
free((void*)source);
EngineNode* node = ALLOCATE(EngineNode, 1);
//BUGFIX: make an inner-interpreter
Interpreter inner;
//init the inner interpreter manually
initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL);
inner.bytecode = tb;
inner.length = size;
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
inner.panic = false;
initLiteralArray(&inner.stack);
inner.exports = interpreter->exports;
inner.exportTypes = interpreter->exportTypes;
inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput);
initEngineNode(node, &inner, tb, size);
//NOTE: initNode() must be called manually
// return the node
Literal nodeLiteral = TO_OPAQUE_LITERAL(node, -1);
pushLiteralArray(&interpreter->stack, nodeLiteral);
//cleanup
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
freeLiteral(fname);
freeLiteral(nodeLiteral);
return 1;
}
static int nativeInitNode(Interpreter* interpreter, LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to initNode\n");
return -1;
}
Literal node = popLiteralArray(arguments);
Literal nodeIdn = node; //annoying
if (!parseIdentifierToValue(interpreter, &node)) {
interpreter->errorOutput("Failed to parse node identifier to value\n");
freeLiteral(node);
return -1;
}
freeLiteral(nodeIdn);
EngineNode* engineNode = AS_OPAQUE(node);
//init the new node
callEngineNode(engineNode, &engine.interpreter, "onInit");
//cleanup
freeLiteral(node);
return 0;
}
static int nativeFreeNode(Interpreter* interpreter, LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to freeNode\n");
return -1;
}
Literal node = popLiteralArray(arguments);
Literal nodeIdn = node; //annoying
if (!parseIdentifierToValue(interpreter, &node)) {
interpreter->errorOutput("Failed to parse node identifier to value\n");
freeLiteral(node);
return -1;
}
freeLiteral(nodeIdn);
EngineNode* engineNode = AS_OPAQUE(node);
//free the node
callEngineNode(engineNode, &engine.interpreter, "onFree");
freeEngineNode(engineNode); //tombstones this node
//cleanup
freeLiteral(node);
return 0;
}
static int nativePushNode(Interpreter* interpreter, LiteralArray* arguments) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to pushNode\n");
return -1;
}
Literal child = popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments);
Literal parentIdn = parent; //annoying
Literal childIdn = child;
if (!parseIdentifierToValue(interpreter, &parent)) {
interpreter->errorOutput("Failed to parse parent identifier to value\n");
freeLiteral(parent);
freeLiteral(child);
return -1;
}
if (!parseIdentifierToValue(interpreter, &child)) {
interpreter->errorOutput("Failed to parse child identifier to value\n");
freeLiteral(parent);
freeLiteral(child);
return -1;
}
freeLiteral(parentIdn);
freeLiteral(childIdn);
if (!IS_OPAQUE(parent) || !IS_OPAQUE(child)) {
interpreter->errorOutput("Incorrect argument type passed to pushNode\n");
freeLiteral(parent);
freeLiteral(child);
return -1;
}
//push the node
EngineNode* parentNode = AS_OPAQUE(parent);
EngineNode* childNode = AS_OPAQUE(child);
pushEngineNode(parentNode, childNode);
//no return value
freeLiteral(parent);
freeLiteral(child);
return 0;
}
static int nativeGetNode(Interpreter* interpreter, LiteralArray* arguments) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to getNode\n");
return -1;
}
Literal index = popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments);
Literal parentIdn = parent; //annoying
if (!parseIdentifierToValue(interpreter, &parent)) {
interpreter->errorOutput("Failed to parse parent identifier to value\n");
freeLiteral(parent);
freeLiteral(index);
return -1;
}
freeLiteral(parentIdn);
if (!IS_OPAQUE(parent) || !IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to getNode\n");
freeLiteral(parent);
freeLiteral(index);
return -1;
}
//push the node
EngineNode* parentNode = AS_OPAQUE(parent);
int intIndex = AS_INTEGER(index);
if (intIndex < 0 || intIndex >= parentNode->count) {
interpreter->errorOutput("index out of bounds in getNode\n");
freeLiteral(parent);
freeLiteral(index);
return -1;
}
EngineNode* childNode = &parentNode->children[intIndex];
Literal child = TO_OPAQUE_LITERAL(childNode, -1);
pushLiteralArray(&interpreter->stack, child);
//no return value
freeLiteral(parent);
freeLiteral(child);
freeLiteral(index);
return 1;
}
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
char* name; char* name;
@@ -141,6 +384,11 @@ int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
Natives natives[] = { Natives natives[] = {
{"initWindow", nativeInitWindow}, {"initWindow", nativeInitWindow},
{"loadRootNode", nativeLoadRootNode}, {"loadRootNode", nativeLoadRootNode},
{"loadNode", nativeLoadNode},
{"initNode", nativeInitNode},
{"freeNode", nativeFreeNode},
{"pushNode", nativePushNode},
{"getNode", nativeGetNode},
{NULL, NULL} {NULL, NULL}
}; };