Playing around with scripts

This commit is contained in:
2023-02-24 22:20:40 +11:00
parent 3fca594209
commit aabbf41dd6
19 changed files with 597 additions and 44 deletions

View File

@@ -21,6 +21,15 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="source\main.c" /> <ClCompile Include="source\main.c" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="assets\scripts\entity.toy" />
<None Include="assets\scripts\init.toy" />
<None Include="assets\scripts\scene.toy" />
<None Include="assets\scripts\tilemap\layer-background.toy" />
<None Include="assets\scripts\tilemap\layer-walls.toy" />
<None Include="assets\scripts\tilemap\tile.toy" />
<None Include="assets\scripts\tilemap\tilemap.toy" />
</ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion> <VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{97F823E5-3AB8-47EF-B142-C15DD7CADF76}</ProjectGuid> <ProjectGuid>{97F823E5-3AB8-47EF-B142-C15DD7CADF76}</ProjectGuid>

View File

@@ -144,6 +144,7 @@ xcopy "$(SolutionDir)Toy\repl\repl_tools.*" "$(SolutionDir)box" /Y /I /E</Comman
<ClCompile Include="box\lib_engine.c" /> <ClCompile Include="box\lib_engine.c" />
<ClCompile Include="box\lib_input.c" /> <ClCompile Include="box\lib_input.c" />
<ClCompile Include="box\lib_node.c" /> <ClCompile Include="box\lib_node.c" />
<ClCompile Include="box\lib_random.c" />
<ClCompile Include="box\lib_runner.c" /> <ClCompile Include="box\lib_runner.c" />
<ClCompile Include="box\lib_standard.c" /> <ClCompile Include="box\lib_standard.c" />
<ClCompile Include="box\repl_tools.c" /> <ClCompile Include="box\repl_tools.c" />
@@ -156,6 +157,7 @@ xcopy "$(SolutionDir)Toy\repl\repl_tools.*" "$(SolutionDir)box" /Y /I /E</Comman
<ClInclude Include="box\lib_engine.h" /> <ClInclude Include="box\lib_engine.h" />
<ClInclude Include="box\lib_input.h" /> <ClInclude Include="box\lib_input.h" />
<ClInclude Include="box\lib_node.h" /> <ClInclude Include="box\lib_node.h" />
<ClInclude Include="box\lib_random.h" />
<ClInclude Include="box\lib_runner.h" /> <ClInclude Include="box\lib_runner.h" />
<ClInclude Include="box\lib_standard.h" /> <ClInclude Include="box\lib_standard.h" />
<ClInclude Include="box\repl_tools.h" /> <ClInclude Include="box\repl_tools.h" />

2
Toy

Submodule Toy updated: d3df01c1c4...3aeddff736

View File

@@ -25,7 +25,7 @@ mapInputEventToKeyUp("character_right", "right"); //event, keysym
//this function must always be called, or the engine won't run //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 //kick off the logic of the scene graph
loadRootNode("scripts:/root.toy"); loadRootNode("scripts:/scene.toy");

View File

@@ -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";
}

23
assets/scripts/scene.toy Normal file
View File

@@ -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");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,2 @@
//EMPTY

View File

@@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

View File

@@ -4,6 +4,7 @@
#include "lib_input.h" #include "lib_input.h"
#include "lib_node.h" #include "lib_node.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "repl_tools.h" #include "repl_tools.h"
@@ -50,6 +51,7 @@ void Box_initEngine() {
//init Toy //init Toy
Toy_initInterpreter(&engine.interpreter); Toy_initInterpreter(&engine.interpreter);
Toy_injectNativeHook(&engine.interpreter, "standard", Toy_hookStandard); 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, "runner", Toy_hookRunner);
Toy_injectNativeHook(&engine.interpreter, "engine", Box_hookEngine); Toy_injectNativeHook(&engine.interpreter, "engine", Box_hookEngine);
Toy_injectNativeHook(&engine.interpreter, "node", Box_hookNode); Toy_injectNativeHook(&engine.interpreter, "node", Box_hookNode);
@@ -338,7 +340,7 @@ void Box_execEngine() {
//set up time //set up time
engine.realTime = clock(); engine.realTime = clock();
engine.simTime = engine.realTime; 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) { while (engine.running) {
execEvents(); execEvents();

View File

@@ -55,6 +55,8 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
//init the inner interpreter manually //init the inner interpreter manually
Toy_initLiteralArray(&inner.literalCache); Toy_initLiteralArray(&inner.literalCache);
Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks;
inner.scope = Toy_pushScope(NULL); inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb; inner.bytecode = tb;
inner.length = size; inner.length = size;
@@ -62,8 +64,6 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
inner.codeStart = -1; inner.codeStart = -1;
inner.depth = interpreter->depth + 1; inner.depth = interpreter->depth + 1;
inner.panic = false; inner.panic = false;
Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks;
Toy_setInterpreterPrint(&inner, interpreter->printOutput); Toy_setInterpreterPrint(&inner, interpreter->printOutput);
Toy_setInterpreterAssert(&inner, interpreter->assertOutput); Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
Toy_setInterpreterError(&inner, interpreter->errorOutput); 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_Literal nodeLiteral = TOY_TO_OPAQUE_LITERAL(node, node->tag);
Toy_pushLiteralArray(&interpreter->stack, nodeLiteral); Toy_pushLiteralArray(&interpreter->stack, nodeLiteral);
//cleanup //cleanup (NOT the scope - that needs to hang around)
while (inner.scope) {
inner.scope = Toy_popScope(inner.scope);
}
Toy_freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache); Toy_freeLiteralArray(&inner.literalCache);
Toy_freeLiteral(filePathLiteral); Toy_freeLiteral(filePathLiteral);
@@ -221,6 +217,11 @@ static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(parentIdn); 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)) { if (!TOY_IS_OPAQUE(parent) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeChild\n"); interpreter->errorOutput("Incorrect argument type passed to getNodeChild\n");
Toy_freeLiteral(parent); Toy_freeLiteral(parent);
@@ -528,15 +529,15 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
return 0; return 0;
} }
static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeCallNodeFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks //checks
if (arguments->count < 2) { if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments passed to callNode\n"); interpreter->errorOutput("Too few arguments passed to callNode\n");
return -1; return -1;
} }
Toy_LiteralArray extraArgs; Toy_LiteralArray extraArgsBackwards;
Toy_initLiteralArray(&extraArgs); Toy_initLiteralArray(&extraArgsBackwards);
//extract the extra arg values //extract the extra arg values
while (arguments->count > 2) { while (arguments->count > 2) {
@@ -547,10 +548,22 @@ static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume
Toy_freeLiteral(idn); 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_pushLiteralArray(&extraArgs, tmp);
Toy_freeLiteral(tmp); Toy_freeLiteral(tmp);
} }
Toy_freeLiteralArray(&extraArgsBackwards);
//back on track //back on track
Toy_Literal fnName = Toy_popLiteralArray(arguments); Toy_Literal fnName = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = 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}, {"freeTexture", nativeFreeTexture},
{"setRect", nativeSetRect}, {"setRect", nativeSetRect},
{"drawNode", nativeDrawNode}, {"drawNode", nativeDrawNode},
{"callNode", nativeCallNode}, {"callNodeFn", nativeCallNodeFn},
//get rect, get node var, create empty node, get child count, get root node
{NULL, NULL}, {NULL, NULL},
}; };

196
box/lib_random.c Normal file
View File

@@ -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;
}

7
box/lib_random.h Normal file
View File

@@ -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

View File

@@ -7,6 +7,49 @@
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
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) { static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 0) { if (arguments->count != 0) {
@@ -702,6 +745,36 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
return 1; 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) { static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 2) { if (arguments->count != 2) {
@@ -1667,6 +1740,7 @@ typedef struct Natives {
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list //build the natives list
Natives natives[] = { Natives natives[] = {
{"abs", nativeAbs},
{"clock", nativeClock}, {"clock", nativeClock},
{"concat", nativeConcat}, //array, dictionary, string {"concat", nativeConcat}, //array, dictionary, string
{"containsKey", nativeContainsKey}, //dictionary {"containsKey", nativeContainsKey}, //dictionary
@@ -1676,6 +1750,7 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
{"forEach", nativeForEach}, //array, dictionary {"forEach", nativeForEach}, //array, dictionary
{"getKeys", nativeGetKeys}, //dictionary {"getKeys", nativeGetKeys}, //dictionary
{"getValues", nativeGetValues}, //dictionary {"getValues", nativeGetValues}, //dictionary
{"hash", nativeHash},
{"indexOf", nativeIndexOf}, //array {"indexOf", nativeIndexOf}, //array
{"map", nativeMap}, //array, dictionary {"map", nativeMap}, //array, dictionary
{"reduce", nativeReduce}, //array, dictionary {"reduce", nativeReduce}, //array, dictionary

View File

@@ -1,6 +1,7 @@
#include "repl_tools.h" #include "repl_tools.h"
#include "lib_about.h" #include "lib_about.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -112,6 +113,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout); Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, (int)size); Toy_runInterpreter(&interpreter, tb, (int)size);