mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Added _forEach and _map, added tests for them
This commit is contained in:
@@ -115,6 +115,81 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nativeForEach(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _forEach\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the args
|
||||
Toy_Literal fnLiteral = Toy_popLiteralArray(arguments);
|
||||
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);
|
||||
}
|
||||
|
||||
Toy_Literal fnLiteralIdn = fnLiteral;
|
||||
if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) {
|
||||
Toy_freeLiteral(fnLiteralIdn);
|
||||
}
|
||||
|
||||
//check type
|
||||
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _forEach\n");
|
||||
Toy_freeLiteral(selfLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//call the given function on each element, based on the compound type
|
||||
if (TOY_IS_ARRAY(selfLiteral)) {
|
||||
for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) {
|
||||
Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i);
|
||||
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]);
|
||||
Toy_pushLiteralArray(&arguments, indexLiteral);
|
||||
|
||||
Toy_LiteralArray returns;
|
||||
Toy_initLiteralArray(&returns);
|
||||
|
||||
Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns);
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteralArray(&returns);
|
||||
Toy_freeLiteral(indexLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
if (TOY_IS_DICTIONARY(selfLiteral)) {
|
||||
for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) {
|
||||
//skip nulls
|
||||
if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key);
|
||||
|
||||
Toy_LiteralArray returns;
|
||||
Toy_initLiteralArray(&returns);
|
||||
|
||||
Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns);
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteralArray(&returns);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _getKeys\n");
|
||||
@@ -205,6 +280,105 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nativeMap(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _map\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the args
|
||||
Toy_Literal fnLiteral = Toy_popLiteralArray(arguments);
|
||||
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);
|
||||
}
|
||||
|
||||
Toy_Literal fnLiteralIdn = fnLiteral;
|
||||
if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) {
|
||||
Toy_freeLiteral(fnLiteralIdn);
|
||||
}
|
||||
|
||||
//check type
|
||||
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _map\n");
|
||||
Toy_freeLiteral(selfLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//call the given function on each element, based on the compound type
|
||||
if (TOY_IS_ARRAY(selfLiteral)) {
|
||||
Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1);
|
||||
Toy_initLiteralArray(returnsPtr);
|
||||
|
||||
for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) {
|
||||
Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i);
|
||||
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]);
|
||||
Toy_pushLiteralArray(&arguments, indexLiteral);
|
||||
|
||||
Toy_LiteralArray returns;
|
||||
Toy_initLiteralArray(&returns);
|
||||
|
||||
Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns);
|
||||
|
||||
//grab the results
|
||||
Toy_Literal lit = Toy_popLiteralArray(&returns);
|
||||
Toy_pushLiteralArray(returnsPtr, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteralArray(&returns);
|
||||
Toy_freeLiteral(indexLiteral);
|
||||
}
|
||||
|
||||
Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr);
|
||||
Toy_pushLiteralArray(&interpreter->stack, returnsLiteral);
|
||||
Toy_freeLiteral(returnsLiteral);
|
||||
}
|
||||
|
||||
if (TOY_IS_DICTIONARY(selfLiteral)) {
|
||||
Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1);
|
||||
Toy_initLiteralArray(returnsPtr);
|
||||
|
||||
for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) {
|
||||
//skip nulls
|
||||
if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value);
|
||||
Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key);
|
||||
|
||||
Toy_LiteralArray returns;
|
||||
Toy_initLiteralArray(&returns);
|
||||
|
||||
Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns);
|
||||
|
||||
//grab the results
|
||||
Toy_Literal lit = Toy_popLiteralArray(&returns);
|
||||
Toy_pushLiteralArray(returnsPtr, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteralArray(&returns);
|
||||
}
|
||||
|
||||
Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr);
|
||||
Toy_pushLiteralArray(&interpreter->stack, returnsLiteral);
|
||||
Toy_freeLiteral(returnsLiteral);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
@@ -477,11 +651,12 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
|
||||
// {"_containsValue", native}, //array, dictionary
|
||||
// {"_every", native}, //array, dictionary, string
|
||||
// {"_filter", native}, //array, dictionary
|
||||
{"_forEach", nativeForEach}, //array, dictionary
|
||||
{"_getKeys", nativeGetKeys}, //dictionary
|
||||
{"_getValues", nativeGetValues}, //dictionary
|
||||
// {"_indexOf", native}, //array, string
|
||||
// {"_insert", native}, //array, dictionary, string
|
||||
// {"_map", native}, //array, dictionary
|
||||
{"_map", nativeMap}, //array, dictionary
|
||||
// {"_reduce", native}, //array, dictionary
|
||||
// {"_remove", native}, //array, dictionary
|
||||
// {"_replace", native}, //string
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import compound;
|
||||
|
||||
|
||||
//test dictionary concat with clashing keys
|
||||
{
|
||||
var a = ["one" : 1, "two": 2, "three": 3, "random": 1];
|
||||
var b = ["four" : 4, "five": 5, "six": 6, "random": 2];
|
||||
|
||||
var c = a.concat(b);
|
||||
|
||||
assert c["random"] == 1, "dictionary.concat() clashing keys failed";
|
||||
}
|
||||
|
||||
print "All good";
|
||||
|
||||
@@ -1187,6 +1187,50 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
}
|
||||
|
||||
bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
|
||||
//check for side-loaded native functions
|
||||
if (TOY_IS_FUNCTION_NATIVE(func)) {
|
||||
//reverse the order to the correct order
|
||||
Toy_LiteralArray correct;
|
||||
Toy_initLiteralArray(&correct);
|
||||
|
||||
while(arguments->count) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(arguments);
|
||||
Toy_pushLiteralArray(&correct, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
//call the native function
|
||||
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
|
||||
|
||||
if (returnsCount < 0) {
|
||||
interpreter->errorOutput("Unknown error from native function\n");
|
||||
Toy_freeLiteralArray(&correct);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the results
|
||||
Toy_LiteralArray returnsFromInner;
|
||||
Toy_initLiteralArray(&returnsFromInner);
|
||||
|
||||
for (int i = 0; i < (returnsCount || 1); i++) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_pushLiteralArray(&returnsFromInner, lit); //NOTE: also reverses the order
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
//flip them around and pass to returns
|
||||
while (returnsFromInner.count > 0) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(&returnsFromInner);
|
||||
Toy_pushLiteralArray(returns, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&returnsFromInner);
|
||||
Toy_freeLiteralArray(&correct);
|
||||
return true;
|
||||
}
|
||||
|
||||
//normal Toy function
|
||||
if (!TOY_IS_FUNCTION(func)) {
|
||||
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import compound;
|
||||
|
||||
//test concat
|
||||
{
|
||||
//test array concat
|
||||
{
|
||||
@@ -44,6 +45,26 @@ import compound;
|
||||
}
|
||||
}
|
||||
|
||||
//test forEach
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
fn p(k, v) {
|
||||
counter++;
|
||||
print string k + ": " + string v;
|
||||
}
|
||||
|
||||
var a = ["a", "b"];
|
||||
var d = ["foo": 1, "bar": 2, "bazz": 3, "fizz": 4];
|
||||
|
||||
a.forEach(p);
|
||||
assert counter == 2, "forEach ran an unusual number of times";
|
||||
|
||||
counter = 0;
|
||||
d.forEach(p);
|
||||
assert counter == 4, "forEach ran an unusual number of times";
|
||||
}
|
||||
|
||||
//test getKeys
|
||||
{
|
||||
var d = ["foo": 1, "bar": 2];
|
||||
@@ -70,6 +91,28 @@ import compound;
|
||||
}
|
||||
|
||||
|
||||
//test map
|
||||
{
|
||||
//test map with toy functions
|
||||
{
|
||||
fn increment(k, v) {
|
||||
return v + 1;
|
||||
}
|
||||
|
||||
var a = [1, 2, 3];
|
||||
var d = ["four": 4, "five": 5, "six": 6];
|
||||
|
||||
assert a.map(increment).map(increment).map(increment) == [4,5,6], "array.map() failed";
|
||||
assert d.map(increment).map(increment).map(increment) == [8,9,7], "dictionary.map() failed";
|
||||
}
|
||||
|
||||
//test map with native functions
|
||||
{
|
||||
//TODO: write some native functions for use with map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//test toLower
|
||||
{
|
||||
assert "Hello World".toLower() == "hello world", "_toLower() failed";
|
||||
|
||||
40
test/scripts/lib/random-stuff.toy
Normal file
40
test/scripts/lib/random-stuff.toy
Normal file
@@ -0,0 +1,40 @@
|
||||
//test this logic for memory leaks
|
||||
{
|
||||
import compound;
|
||||
import timer;
|
||||
|
||||
fn start(k, v) {
|
||||
return startTimer();
|
||||
}
|
||||
|
||||
fn check(k, v) {
|
||||
var l = v.stopTimer();
|
||||
print l.timerToString();
|
||||
l.destroyTimer();
|
||||
return v;
|
||||
}
|
||||
|
||||
fn destroy(k, v) {
|
||||
v.destroyTimer();
|
||||
}
|
||||
|
||||
var arr = [1];
|
||||
|
||||
arr
|
||||
.map(start)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(check)
|
||||
.map(destroy)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -53,6 +53,26 @@ void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_Hoo
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
void runBinaryQuietly(unsigned char* tb, size_t size) {
|
||||
Toy_Interpreter interpreter;
|
||||
Toy_initInterpreter(&interpreter);
|
||||
|
||||
//NOTE: supress print output for testing
|
||||
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||
Toy_setInterpreterAssert(&interpreter, assertWrapper);
|
||||
Toy_setInterpreterError(&interpreter, errorWrapper);
|
||||
|
||||
//inject the libs
|
||||
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
|
||||
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
|
||||
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);
|
||||
}
|
||||
|
||||
typedef struct Payload {
|
||||
char* fname;
|
||||
char* libname;
|
||||
@@ -111,6 +131,41 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//run whatever, testing stuff together to check for memory leaks
|
||||
char* whatever[] = {
|
||||
"random-stuff.toy",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i = 0; whatever[i]; i++) {
|
||||
printf("Running %s\n", whatever[i]);
|
||||
|
||||
char fname[128];
|
||||
snprintf(fname, 128, "scripts/lib/%s", whatever[i]);
|
||||
|
||||
//compile the source
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
if (!source) {
|
||||
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
|
||||
failedAsserts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
if (!tb) {
|
||||
printf(TOY_CC_ERROR "Failed to compile file: %s\n" TOY_CC_RESET, fname);
|
||||
failedAsserts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
runBinaryQuietly(tb, size);
|
||||
}
|
||||
}
|
||||
|
||||
//lib cleanup
|
||||
Toy_freeDriveDictionary();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user