From aabbf41dd60ddc9e4bf29c38f3416bebd8602419 Mon Sep 17 00:00:00 2001 From: Ratstail91 Date: Fri, 24 Feb 2023 22:20:40 +1100 Subject: [PATCH] Playing around with scripts --- Airport.vcxproj | 9 + Box.vcxproj | 2 + Toy | 2 +- assets/scripts/init.toy | 4 +- assets/scripts/root.toy | 29 --- assets/scripts/scene.toy | 23 +++ assets/scripts/tilemap/layer-background.toy | 70 +++++++ assets/scripts/tilemap/layer-walls.toy | 84 +++++++++ assets/scripts/tilemap/tile.toy | 2 + assets/scripts/tilemap/tilemap.toy | 95 ++++++++++ assets/sprites/character.png | Bin 700 -> 0 bytes assets/sprites/tile-background.png | Bin 0 -> 179 bytes assets/sprites/tile-wall.png | Bin 0 -> 179 bytes box/box_engine.c | 4 +- box/lib_node.c | 37 ++-- box/lib_random.c | 196 ++++++++++++++++++++ box/lib_random.h | 7 + box/lib_standard.c | 75 ++++++++ box/repl_tools.c | 2 + 19 files changed, 597 insertions(+), 44 deletions(-) delete mode 100644 assets/scripts/root.toy create mode 100644 assets/scripts/scene.toy create mode 100644 assets/scripts/tilemap/layer-background.toy create mode 100644 assets/scripts/tilemap/layer-walls.toy create mode 100644 assets/scripts/tilemap/tile.toy create mode 100644 assets/scripts/tilemap/tilemap.toy delete mode 100644 assets/sprites/character.png create mode 100644 assets/sprites/tile-background.png create mode 100644 assets/sprites/tile-wall.png create mode 100644 box/lib_random.c create mode 100644 box/lib_random.h 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 acf6c8a6aeb26512d824414424af29064429762d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 700 zcmV;t0z>_YP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!ToQXn;|AH3?z+18K4s- zQ4`TH;2<#u8R*bfX)G%8yFKr{`{?U?_qM%@-_mngK7RMyd+v)&t>@0jAQt}`<3A7# z*Z**71}pov#-$mo`|qk;n!!qaKB4R1e(|#Rh$cUNb1W7n5Q4iOYQ|DH$JA5`M_?+2 zRZI?ZX(omBVlly`nH1Lk)j=|uLiE673L!9=!Z}43Q^c#kdDR_`04cVoFYyYJA6#{Z zBLIc;2vs@mfsO(bF@^?EMsVH+Te~bi+-t(1Sj- z2;@E>0g`k>i{Ri&ln&!jQKJVp59*@slokOfCf#kapVV9DX;zlMQm#}HYgK#&TeI%1 z&g`9t-)F1e3D4`(S4U#4im%|)WQ=ODK2cAU8#ME!?%eFYzj{6K6*LASRFdulwg-Q+ zc~mHK6^^d}Y$k`eBFet6(%PL-Ug-_PwgM!u|Le)425qF=TYwX_^k9rvO@gMYwgBWam$?e3BLR>{ icMu&5!lvI6;>1s;*b3=DinK$vl=HlH+5(8JTkF(ktM?R7_91_d6LgUrPq2e_F&1aYol zX3BVAx7%~_H}m^yp2huZnI+cVdtJP={nPDSMxaJy@a%g`l!XqP^)lnF${=x1S3j3^ HP6!lvI6;>1s;*b3=DinK$vl=HlH+5(8JTkF(ktM?R7(51_d6Mi_GkAI-Il??NVms zSkM^#&wtjI+tIUC&f0F{OK{nL{kd1}sr>CA!;ry@`^A}zYo4%Kvn_kP6(r&5>gTe~ HDWM4fKMpY& literal 0 HcmV?d00001 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);