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;
|
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) {
|
static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _getKeys\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getKeys\n");
|
||||||
@@ -205,6 +280,105 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
|||||||
return 1;
|
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) {
|
static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
@@ -477,11 +651,12 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
|
|||||||
// {"_containsValue", native}, //array, dictionary
|
// {"_containsValue", native}, //array, dictionary
|
||||||
// {"_every", native}, //array, dictionary, string
|
// {"_every", native}, //array, dictionary, string
|
||||||
// {"_filter", native}, //array, dictionary
|
// {"_filter", native}, //array, dictionary
|
||||||
|
{"_forEach", nativeForEach}, //array, dictionary
|
||||||
{"_getKeys", nativeGetKeys}, //dictionary
|
{"_getKeys", nativeGetKeys}, //dictionary
|
||||||
{"_getValues", nativeGetValues}, //dictionary
|
{"_getValues", nativeGetValues}, //dictionary
|
||||||
// {"_indexOf", native}, //array, string
|
// {"_indexOf", native}, //array, string
|
||||||
// {"_insert", native}, //array, dictionary, string
|
// {"_insert", native}, //array, dictionary, string
|
||||||
// {"_map", native}, //array, dictionary
|
{"_map", nativeMap}, //array, dictionary
|
||||||
// {"_reduce", native}, //array, dictionary
|
// {"_reduce", native}, //array, dictionary
|
||||||
// {"_remove", native}, //array, dictionary
|
// {"_remove", native}, //array, dictionary
|
||||||
// {"_replace", native}, //string
|
// {"_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) {
|
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)) {
|
if (!TOY_IS_FUNCTION(func)) {
|
||||||
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
|
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import compound;
|
import compound;
|
||||||
|
|
||||||
|
//test concat
|
||||||
{
|
{
|
||||||
//test array 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
|
//test getKeys
|
||||||
{
|
{
|
||||||
var d = ["foo": 1, "bar": 2];
|
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
|
//test toLower
|
||||||
{
|
{
|
||||||
assert "Hello World".toLower() == "hello world", "_toLower() failed";
|
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);
|
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 {
|
typedef struct Payload {
|
||||||
char* fname;
|
char* fname;
|
||||||
char* libname;
|
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
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user