diff --git a/Airport.vcxproj b/Airport.vcxproj
index f7e824b..75be58d 100644
--- a/Airport.vcxproj
+++ b/Airport.vcxproj
@@ -21,6 +21,15 @@
+
+
+
+
+
+
+
+
+
17.0
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}
diff --git a/Box.vcxproj b/Box.vcxproj
index 7edb6ee..cc3e017 100644
--- a/Box.vcxproj
+++ b/Box.vcxproj
@@ -144,6 +144,7 @@ xcopy "$(SolutionDir)Toy\repl\repl_tools.*" "$(SolutionDir)box" /Y /I /E
+
@@ -156,6 +157,7 @@ xcopy "$(SolutionDir)Toy\repl\repl_tools.*" "$(SolutionDir)box" /Y /I /E
+
diff --git a/Toy b/Toy
index d3df01c..3aeddff 160000
--- a/Toy
+++ b/Toy
@@ -1 +1 @@
-Subproject commit d3df01c1c4ae625fb7a3a36eb0ae8afee31bfefa
+Subproject commit 3aeddff736945f953bb7865678405091f06567ef
diff --git a/assets/scripts/init.toy b/assets/scripts/init.toy
index 4e1ad0b..eddaf2c 100644
--- a/assets/scripts/init.toy
+++ b/assets/scripts/init.toy
@@ -25,7 +25,7 @@ mapInputEventToKeyUp("character_right", "right"); //event, keysym
//this function must always be called, or the engine won't run
-initWindow("Airport Game", 800, 600, false);
+initWindow("Airport Game", 1080, 720, false);
//kick off the logic of the scene graph
-loadRootNode("scripts:/root.toy");
+loadRootNode("scripts:/scene.toy");
diff --git a/assets/scripts/root.toy b/assets/scripts/root.toy
deleted file mode 100644
index f19cfcb..0000000
--- a/assets/scripts/root.toy
+++ /dev/null
@@ -1,29 +0,0 @@
-//import standard;
-import engine;
-import node;
-
-//util to generate and init a child node of a parent
-fn makeChild(parent: opaque, fname: string) {
- var child: opaque = loadNode(fname);
- parent.pushNode(child);
- child.initNode();
-}
-
-//NOTE: 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
- node.makeChild("scripts:/entity.toy");
-
- //give the child a child
- // node.getNodeChild(0).makeChild("scripts:/entity.toy");
-}
-
-fn onStep(node: opaque) {
- //print clock();
-}
-
-fn onFree(node: opaque) {
- print "root.toy:onFree() called";
-}
diff --git a/assets/scripts/scene.toy b/assets/scripts/scene.toy
new file mode 100644
index 0000000..41ed902
--- /dev/null
+++ b/assets/scripts/scene.toy
@@ -0,0 +1,23 @@
+//the overarching scene
+import node;
+
+
+//util to generate and init a child node of a given parent
+fn makeChild(parent: opaque, fname: string) {
+ var child: opaque = loadNode(fname);
+ parent.pushNode(child);
+ child.initNode();
+ return child;
+}
+
+
+fn onInit(node: opaque) {
+ //load the tile map node
+ var tilemapNode = node.makeChild("scripts:/tilemap/tilemap.toy");
+
+ tilemapNode.callNodeFn("loadLayer", "layer-background.toy");
+ tilemapNode.callNodeFn("loadLayer", "layer-walls.toy");
+ tilemapNode.callNodeFn("loadLayer", "layer-walls.toy");
+ //tilemapNode.callNodeFn("loadLayer", "layer-walls.toy"); //TODO: remove this
+ //tilemapNode.callNodeFn("loadLayer", "layer-maze.toy");
+}
diff --git a/assets/scripts/tilemap/layer-background.toy b/assets/scripts/tilemap/layer-background.toy
new file mode 100644
index 0000000..585adb5
--- /dev/null
+++ b/assets/scripts/tilemap/layer-background.toy
@@ -0,0 +1,70 @@
+//this is one layer
+import node;
+
+var childCounter: int = 0;
+
+//TODO: reference these from a global source (root?)
+var tileWidth: float const = 100;
+var tileHeight: float const = 100;
+
+var roomWidth: float const = 10;
+var roomHeight: float const = 10;
+
+
+//util to generate and init a child node of a given parent
+fn makeChildSprite(parent: opaque, spriteName: string) {
+ var child: opaque = loadNode("scripts:/tilemap/tile.toy");
+ parent.pushNode(child);
+ child.initNode();
+
+ child.loadTexture("sprites:/" + spriteName);
+
+ //BUGFIX
+ childCounter++;
+
+ return child;
+}
+
+
+fn onInit(node: opaque) {
+ //load the child node, with the tiling back image
+ node.makeChildSprite("tile-background.png");
+}
+
+fn drawRoom(node: opaque, x, y, depth, camX, camY, camW, camH) {
+ //the modifier ratio to move things
+ var mod: float = float tileWidth / (tileWidth - depth);
+
+ var tileWidth_mod = tileWidth * mod;
+ var tileHeight_mod = tileHeight * mod;
+ var camX_mod = (camX - camW) * mod + camW / 2;
+ var camY_mod = (camY - camH) * mod + camH / 2;
+
+ for (var j: int = 0; j < roomHeight; j++) {
+ for (var i: int = 0; i < roomWidth; i++) {
+ node.getNodeChild(0).drawNode(round( (x * roomWidth + i) * tileWidth_mod + camX_mod ),round( (y * roomHeight + j) * tileHeight_mod + camY_mod ), round( tileWidth_mod ), round( tileHeight_mod ));
+ }
+ }
+}
+
+fn round(x): int {
+ var f = floor(x);
+ return x - f >= 0.5 ? f + 1 : f;
+}
+
+fn floor(x): int {
+ return int x;
+}
+
+fn ceil(x): int {
+ var f = floor(x);
+ return x - f != 0 ? f + 1 : f;
+}
+
+fn min(a, b) {
+ return a < b ? a : b;
+}
+
+fn max(a, b) {
+ return a > b ? a : b;
+}
\ No newline at end of file
diff --git a/assets/scripts/tilemap/layer-walls.toy b/assets/scripts/tilemap/layer-walls.toy
new file mode 100644
index 0000000..47404a7
--- /dev/null
+++ b/assets/scripts/tilemap/layer-walls.toy
@@ -0,0 +1,84 @@
+//this is one layer
+import node;
+
+var childCounter: int = 0;
+
+//TODO: reference these from a global source (root?)
+var tileWidth: float const = 100;
+var tileHeight: float const = 100;
+
+var roomWidth: float const = 10;
+var roomHeight: float const = 10;
+
+
+//util to generate and init a child node of a given parent
+fn makeChildSprite(parent: opaque, spriteName: string) {
+ var child: opaque = loadNode("scripts:/tilemap/tile.toy");
+ parent.pushNode(child);
+ child.initNode();
+
+ child.loadTexture("sprites:/" + spriteName);
+
+ //BUGFIX
+ childCounter++;
+
+ return child;
+}
+
+
+fn onInit(node: opaque) {
+ //load the child node, with the tiling back image
+ node.makeChildSprite("tile-wall.png");
+}
+
+//draw the parallax-style walls
+fn drawRoom(node: opaque, x, y, depth, camX, camY, camW, camH) {
+ var mod: float = float tileWidth / (tileWidth - depth);
+
+ var tileWidth_mod = tileWidth * mod;
+ var tileHeight_mod = tileHeight * mod;
+ var camX_mod = (camX - camW) * mod + camW / 2;
+ var camY_mod = (camY - camH) * mod + camH / 2;
+
+ //top
+ for (var i = x * roomWidth; i < (x * roomWidth) + roomWidth; i++) {
+ node.getNodeChild(0).drawNode(round( i * tileWidth_mod + camX_mod ), round(y * roomHeight * tileHeight_mod + camY_mod ), round( tileWidth_mod), round( tileHeight_mod ));
+ }
+
+ //left
+ for (var j = y * roomHeight; j < (y * roomHeight) + roomHeight; j++) {
+ node.getNodeChild(0).drawNode(round( x * roomWidth * tileWidth_mod + camX_mod ), round( j * tileHeight_mod + camY_mod ), round( tileWidth_mod), round( tileHeight_mod ));
+ }
+
+ //bottom
+ for (var i = x * roomWidth; i < (x * roomWidth) + roomWidth; i++) {
+ node.getNodeChild(0).drawNode(round( i * tileWidth_mod + camX_mod), round( ((y+1) * roomHeight -1) * tileHeight_mod + camY_mod), round( tileWidth_mod), round( tileHeight_mod));
+ }
+
+ //right
+ for (var j = y * roomHeight; j < (y * roomHeight) + roomHeight; j++) {
+ node.getNodeChild(0).drawNode(round( ((x + 1) * roomWidth -1) * tileWidth_mod + camX_mod ), round( j * tileHeight_mod + camY_mod ), round( tileWidth_mod ), round( tileHeight_mod ));
+ }
+}
+
+fn round(x): int {
+ var f = floor(x);
+ return x - f >= 0.5 ? f + 1 : f;
+}
+
+fn floor(x): int {
+ return int x;
+}
+
+fn ceil(x): int {
+ var f = floor(x);
+ return x - f != 0 ? f + 1 : f;
+}
+
+fn min(a, b) {
+ return a < b ? a : b;
+}
+
+fn max(a, b) {
+ return a > b ? a : b;
+}
\ No newline at end of file
diff --git a/assets/scripts/tilemap/tile.toy b/assets/scripts/tilemap/tile.toy
new file mode 100644
index 0000000..29c12b7
--- /dev/null
+++ b/assets/scripts/tilemap/tile.toy
@@ -0,0 +1,2 @@
+//EMPTY
+
diff --git a/assets/scripts/tilemap/tilemap.toy b/assets/scripts/tilemap/tilemap.toy
new file mode 100644
index 0000000..d6b6e16
--- /dev/null
+++ b/assets/scripts/tilemap/tilemap.toy
@@ -0,0 +1,95 @@
+//this file manages the tilemap-related utilities
+import standard;
+import node;
+
+var childCounter: int = 0;
+
+var levelXCount: int const = 4;
+var levelYCount: int const = 4;
+
+var camX: float = 0;
+var camY: float = 0;
+
+//TODO: reference these from a global source (root?)
+var tileWidth: float const = 100;
+var tileHeight: float const = 100;
+
+var roomWidth: float const = 10;
+var roomHeight: float const = 10;
+
+var screenWidth: float = 1080;
+var screenHeight: float = 720;
+
+
+//util to generate and init a child node of a given parent
+fn makeChild(parent: opaque, fname: string) {
+ var child: opaque = loadNode(fname);
+ parent.pushNode(child);
+ child.initNode();
+ return child;
+}
+
+fn loadLayer(node: opaque, layerName: string) {
+ //load the given layer as a child
+ var layerNode = node.makeChild("scripts:/tilemap/" + layerName);
+ childCounter++;
+}
+
+var stepCounter = 0;
+fn onStep(node: opaque) {
+ stepCounter++;
+
+ camX--;
+ camY--;
+}
+
+fn onDraw(node: opaque) {
+ print stepCounter;
+ stepCounter = 0;
+
+ //TODO: reference the camera width & height
+ //TODO: render parallax
+
+ //cull out-of-bounds regions
+ var lowerX = abs(floor(floor((camX-screenWidth/2) / tileWidth) / float roomWidth));
+ var upperX = abs(ceil(floor((camX-screenWidth*1.5) / float tileWidth) / float roomWidth));
+
+ var lowerY = abs(floor(floor((camY-screenHeight/2) / tileHeight) / float roomHeight));
+ var upperY = abs(ceil(floor((camY-screenHeight*1.5) / float tileHeight) / float roomHeight));
+
+ //bounds check
+ lowerX = max(lowerX, 0);
+ upperX = min(upperX + 1, levelXCount);
+ lowerY = max(lowerY, 0);
+ upperY = min(upperY + 1, levelYCount);
+
+ for (var c = 0; c < childCounter; c++) {
+ for (var j = lowerY; j <= upperY; j++) {
+ for (var i = lowerX; i <= upperX; i++) {
+ node.getNodeChild(c).callNodeFn("drawRoom", i, j, c * 4.0, camX, camY, screenWidth, screenHeight);
+ }
+ }
+ }
+}
+
+fn round(x): int {
+ var f = floor(x);
+ return x - f >= 0.5 ? f + 1 : f;
+}
+
+fn floor(x): int {
+ return int x;
+}
+
+fn ceil(x): int {
+ var f = floor(x);
+ return x - f != 0 ? f + 1 : f;
+}
+
+fn min(a, b) {
+ return a < b ? a : b;
+}
+
+fn max(a, b) {
+ return a > b ? a : b;
+}
\ No newline at end of file
diff --git a/assets/sprites/character.png b/assets/sprites/character.png
deleted file mode 100644
index acf6c8a..0000000
Binary files a/assets/sprites/character.png and /dev/null differ
diff --git a/assets/sprites/tile-background.png b/assets/sprites/tile-background.png
new file mode 100644
index 0000000..b7b5a80
Binary files /dev/null and b/assets/sprites/tile-background.png differ
diff --git a/assets/sprites/tile-wall.png b/assets/sprites/tile-wall.png
new file mode 100644
index 0000000..0bd96a5
Binary files /dev/null and b/assets/sprites/tile-wall.png differ
diff --git a/box/box_engine.c b/box/box_engine.c
index 60f6fdd..14bb6cf 100644
--- a/box/box_engine.c
+++ b/box/box_engine.c
@@ -4,6 +4,7 @@
#include "lib_input.h"
#include "lib_node.h"
#include "lib_standard.h"
+#include "lib_random.h"
#include "lib_runner.h"
#include "repl_tools.h"
@@ -50,6 +51,7 @@ void Box_initEngine() {
//init Toy
Toy_initInterpreter(&engine.interpreter);
Toy_injectNativeHook(&engine.interpreter, "standard", Toy_hookStandard);
+ Toy_injectNativeHook(&engine.interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&engine.interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&engine.interpreter, "engine", Box_hookEngine);
Toy_injectNativeHook(&engine.interpreter, "node", Box_hookNode);
@@ -338,7 +340,7 @@ void Box_execEngine() {
//set up time
engine.realTime = clock();
engine.simTime = engine.realTime;
- clock_t delta = (double) CLOCKS_PER_SEC / 240.0;
+ clock_t delta = (double) CLOCKS_PER_SEC / 60.0;
while (engine.running) {
execEvents();
diff --git a/box/lib_node.c b/box/lib_node.c
index ea0045d..1cb26f8 100644
--- a/box/lib_node.c
+++ b/box/lib_node.c
@@ -55,6 +55,8 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
//init the inner interpreter manually
Toy_initLiteralArray(&inner.literalCache);
+ Toy_initLiteralArray(&inner.stack);
+ inner.hooks = interpreter->hooks;
inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb;
inner.length = size;
@@ -62,8 +64,6 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
inner.panic = false;
- Toy_initLiteralArray(&inner.stack);
- inner.hooks = interpreter->hooks;
Toy_setInterpreterPrint(&inner, interpreter->printOutput);
Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
Toy_setInterpreterError(&inner, interpreter->errorOutput);
@@ -74,11 +74,7 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
Toy_Literal nodeLiteral = TOY_TO_OPAQUE_LITERAL(node, node->tag);
Toy_pushLiteralArray(&interpreter->stack, nodeLiteral);
- //cleanup
- while (inner.scope) {
- inner.scope = Toy_popScope(inner.scope);
- }
-
+ //cleanup (NOT the scope - that needs to hang around)
Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache);
Toy_freeLiteral(filePathLiteral);
@@ -221,6 +217,11 @@ static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(parentIdn);
}
+ Toy_Literal indexIdn = index;
+ if (TOY_IS_IDENTIFIER(index) && Toy_parseIdentifierToValue(interpreter, &index)) {
+ Toy_freeLiteral(indexIdn);
+ }
+
if (!TOY_IS_OPAQUE(parent) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeChild\n");
Toy_freeLiteral(parent);
@@ -528,15 +529,15 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
return 0;
}
-static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+static int nativeCallNodeFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments passed to callNode\n");
return -1;
}
- Toy_LiteralArray extraArgs;
- Toy_initLiteralArray(&extraArgs);
+ Toy_LiteralArray extraArgsBackwards;
+ Toy_initLiteralArray(&extraArgsBackwards);
//extract the extra arg values
while (arguments->count > 2) {
@@ -547,10 +548,22 @@ static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
Toy_freeLiteral(idn);
}
+ Toy_pushLiteralArray(&extraArgsBackwards, tmp);
+ Toy_freeLiteral(tmp);
+ }
+
+ //reverse the extra args
+ Toy_LiteralArray extraArgs;
+ Toy_initLiteralArray(&extraArgs);
+
+ while (extraArgsBackwards.count > 0) {
+ Toy_Literal tmp = Toy_popLiteralArray(&extraArgsBackwards);
Toy_pushLiteralArray(&extraArgs, tmp);
Toy_freeLiteral(tmp);
}
+ Toy_freeLiteralArray(&extraArgsBackwards);
+
//back on track
Toy_Literal fnName = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
@@ -609,7 +622,9 @@ int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter
{"freeTexture", nativeFreeTexture},
{"setRect", nativeSetRect},
{"drawNode", nativeDrawNode},
- {"callNode", nativeCallNode},
+ {"callNodeFn", nativeCallNodeFn},
+
+ //get rect, get node var, create empty node, get child count, get root node
{NULL, NULL},
};
diff --git a/box/lib_random.c b/box/lib_random.c
new file mode 100644
index 0000000..6b70cc8
--- /dev/null
+++ b/box/lib_random.c
@@ -0,0 +1,196 @@
+#include "lib_random.h"
+
+#include "toy_memory.h"
+
+static int hashInt(int x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ return x;
+}
+
+typedef struct Toy_RandomGenerator {
+ int seed; //mutated with each call
+} Toy_RandomGenerator;
+
+//Toy native functions
+static int nativeCreateRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+ //arguments
+ if (arguments->count != 1) {
+ interpreter->errorOutput("Incorrect number of arguments to createRandomGenerator\n");
+ return -1;
+ }
+
+ //get the seed argument
+ Toy_Literal seedLiteral = Toy_popLiteralArray(arguments);
+
+ Toy_Literal seedLiteralIdn = seedLiteral;
+ if (TOY_IS_IDENTIFIER(seedLiteral) && Toy_parseIdentifierToValue(interpreter, &seedLiteral)) {
+ Toy_freeLiteral(seedLiteralIdn);
+ }
+
+ if (TOY_IS_IDENTIFIER(seedLiteral)) {
+ Toy_freeLiteral(seedLiteral);
+ return -1;
+ }
+
+ if (!TOY_IS_INTEGER(seedLiteral)) {
+ interpreter->errorOutput("Incorrect literal type passed to createRandomGenerator");
+ Toy_freeLiteral(seedLiteral);
+ return -1;
+ }
+
+ //generate the generator object
+ Toy_RandomGenerator* generator = TOY_ALLOCATE(Toy_RandomGenerator, 1);
+ generator->seed = TOY_AS_INTEGER(seedLiteral);
+ Toy_Literal generatorLiteral = TOY_TO_OPAQUE_LITERAL(generator, TOY_OPAQUE_TAG_RANDOM);
+
+ //return and cleanup
+ Toy_pushLiteralArray(&interpreter->stack, generatorLiteral);
+
+ Toy_freeLiteral(seedLiteral);
+ Toy_freeLiteral(generatorLiteral);
+
+ return 1;
+}
+
+static int nativeGenerateRandomNumber(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+ //no arguments
+ if (arguments->count != 1) {
+ interpreter->errorOutput("Incorrect number of arguments to generateRandomNumber\n");
+ return -1;
+ }
+
+ //get the runner object
+ Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
+
+ Toy_Literal generatorLiteralIdn = generatorLiteral;
+ if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
+ Toy_freeLiteral(generatorLiteralIdn);
+ }
+
+ if (TOY_IS_IDENTIFIER(generatorLiteral)) {
+ Toy_freeLiteral(generatorLiteral);
+ return -1;
+ }
+
+ if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
+ interpreter->errorOutput("Unrecognized opaque literal in generateRandomNumber\n");
+ return -1;
+ }
+
+ Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
+
+ //generate the new value and package up the return
+ generator->seed = hashInt(generator->seed);
+
+ Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(generator->seed);
+
+ Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
+
+ //cleanup
+ Toy_freeLiteral(generatorLiteral);
+ Toy_freeLiteral(resultLiteral);
+
+ return 0;
+}
+
+static int nativeFreeRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+ //no arguments
+ if (arguments->count != 1) {
+ interpreter->errorOutput("Incorrect number of arguments to freeRandomGenerator\n");
+ return -1;
+ }
+
+ //get the runner object
+ Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
+
+ Toy_Literal generatorLiteralIdn = generatorLiteral;
+ if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
+ Toy_freeLiteral(generatorLiteralIdn);
+ }
+
+ if (TOY_IS_IDENTIFIER(generatorLiteral)) {
+ Toy_freeLiteral(generatorLiteral);
+ return -1;
+ }
+
+ if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
+ interpreter->errorOutput("Unrecognized opaque literal in freeRandomGenerator\n");
+ return -1;
+ }
+
+ Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
+
+ //clear out the runner object
+ TOY_FREE(Toy_RandomGenerator, generator);
+ Toy_freeLiteral(generatorLiteral);
+
+ return 0;
+}
+
+//call the hook
+typedef struct Natives {
+ const char* name;
+ Toy_NativeFn fn;
+} Natives;
+
+int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
+ //build the natives list
+ Natives natives[] = {
+ {"createRandomGenerator", nativeCreateRandomGenerator},
+ {"generateRandomNumber", nativeGenerateRandomNumber},
+ {"freeRandomGenerator", nativeFreeRandomGenerator},
+ {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 -1;
+ }
+
+ //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_NATIVE_LITERAL(natives[i].fn);
+
+ 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;
+}
diff --git a/box/lib_random.h b/box/lib_random.h
new file mode 100644
index 0000000..2dfae4d
--- /dev/null
+++ b/box/lib_random.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "toy_interpreter.h"
+
+int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+
+#define TOY_OPAQUE_TAG_RANDOM 200
diff --git a/box/lib_standard.c b/box/lib_standard.c
index d7d5a8c..4375488 100644
--- a/box/lib_standard.c
+++ b/box/lib_standard.c
@@ -7,6 +7,49 @@
#include
#include
+static int nativeAbs(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+ if (arguments->count != 1) {
+ interpreter->errorOutput("Incorrect number of arguments to abs\n");
+ return -1;
+ }
+
+ //get the self
+ Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
+
+ //parse to value if needed
+ Toy_Literal selfLiteralIdn = selfLiteral;
+ if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
+ Toy_freeLiteral(selfLiteralIdn);
+ }
+
+ if (TOY_IS_IDENTIFIER(selfLiteral)) {
+ Toy_freeLiteral(selfLiteral);
+ return -1;
+ }
+
+ if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
+ interpreter->errorOutput("Incorrect argument type passed to abs\n");
+ Toy_freeLiteral(selfLiteral);
+ return -1;
+ }
+
+ Toy_Literal result;
+
+ if (TOY_IS_INTEGER(selfLiteral)) {
+ result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(selfLiteral) > 0 ? TOY_AS_INTEGER(selfLiteral) : -TOY_AS_INTEGER(selfLiteral) );
+ }
+ if (TOY_IS_FLOAT(selfLiteral)) {
+ result = TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(selfLiteral) > 0 ? TOY_AS_FLOAT(selfLiteral) : -TOY_AS_FLOAT(selfLiteral) );
+ }
+
+ Toy_pushLiteralArray(&interpreter->stack, result);
+
+ Toy_freeLiteral(result);
+ Toy_freeLiteral(selfLiteral);
+
+ return 1;
+}
+
static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
@@ -702,6 +745,36 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
return 1;
}
+static int nativeHash(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
+ if (arguments->count != 1) {
+ interpreter->errorOutput("Incorrect number of arguments to hash\n");
+ return -1;
+ }
+
+ //get the self
+ Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
+
+ //parse to value if needed
+ Toy_Literal selfLiteralIdn = selfLiteral;
+ if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
+ Toy_freeLiteral(selfLiteralIdn);
+ }
+
+ if (TOY_IS_IDENTIFIER(selfLiteral)) {
+ Toy_freeLiteral(selfLiteral);
+ return -1;
+ }
+
+ Toy_Literal result = TOY_TO_INTEGER_LITERAL(Toy_hashLiteral(selfLiteral));
+
+ Toy_pushLiteralArray(&interpreter->stack, result);
+
+ Toy_freeLiteral(result);
+ Toy_freeLiteral(selfLiteral);
+
+ return 1;
+}
+
static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
@@ -1667,6 +1740,7 @@ typedef struct Natives {
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
+ {"abs", nativeAbs},
{"clock", nativeClock},
{"concat", nativeConcat}, //array, dictionary, string
{"containsKey", nativeContainsKey}, //dictionary
@@ -1676,6 +1750,7 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
{"forEach", nativeForEach}, //array, dictionary
{"getKeys", nativeGetKeys}, //dictionary
{"getValues", nativeGetValues}, //dictionary
+ {"hash", nativeHash},
{"indexOf", nativeIndexOf}, //array
{"map", nativeMap}, //array, dictionary
{"reduce", nativeReduce}, //array, dictionary
diff --git a/box/repl_tools.c b/box/repl_tools.c
index 0b46080..e26b861 100644
--- a/box/repl_tools.c
+++ b/box/repl_tools.c
@@ -1,6 +1,7 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_standard.h"
+#include "lib_random.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
@@ -112,6 +113,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
+ Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, (int)size);