TegraExplorer/source/script/arrayClass.c

308 lines
8.4 KiB
C

#include "model.h"
#include "compat.h"
#include "genericClass.h"
#include "intClass.h"
#include "arrayClass.h"
#include "garbageCollector.h"
#include "eval.h"
#include "scriptError.h"
#include "StringClass.h"
#include <string.h>
u8 anotherOneIntArg[] = { IntClass };
u8 oneStringoneFunction[] = { StringClass, FunctionClass };
u8 doubleInt[] = {IntClass, IntClass};
u8 oneIntOneAny[] = { IntClass, VARARGCOUNT };
u8 anotherAnotherOneVarArg[] = { VARARGCOUNT };
u8 oneByteArrayClass[] = {ByteArrayClass};
u8 oneIntArrayClass[] = {IntArrayClass};
Variable_t arrayClassGetIdx(Variable_t *caller, s64 idx) {
if (caller->variableType == IntArrayClass) {
s64* arr = caller->solvedArray.vector.data;
return newIntVariable(arr[idx]);
}
else if (caller->variableType == StringArrayClass) {
char** arr = caller->solvedArray.vector.data;
Variable_t v = newStringVariable(arr[idx], 1, 0);
v.readOnly = 1;
v.reference = 1;
return v;
}
else if (caller->variableType == ByteArrayClass) {
u8* arr = caller->solvedArray.vector.data;
return newIntVariable(arr[idx]);
}
return (Variable_t) { 0 };
}
int arrayClassAdd(Variable_t *caller, Variable_t *add){
if (caller->variableType == IntArrayClass) {
if (add->variableType != IntClass) {
return 1;
}
vecAdd(&caller->solvedArray.vector, add->integer.value);
}
else if (caller->variableType == StringArrayClass) {
if (add->variableType != StringClass) {
return 1;
}
char* str = CpyStr(add->string.value);
vecAdd(&caller->solvedArray.vector, str);
}
else if (caller->variableType == ByteArrayClass) {
if (add->variableType != IntClass) {
return 1;
}
u8 val = (u8)(add->integer.value & 0xFF);
vecAdd(&caller->solvedArray.vector, val);
}
return 0;
}
int arrayClassAddRange(Variable_t* caller, Variable_t* add)
{
// Check if IntArrayClass or StringArrayClass or ByteArrayClass
if ((caller->variableType == IntArrayClass) || (caller->variableType == StringArrayClass) || (caller->variableType == ByteArrayClass)) {
if (caller->variableType != add->variableType) {
return 1;
}
for (s64 i = 0; i < add->solvedArray.vector.count; i++)
{
Variable_t v = arrayClassGetIdx(add, i);
if (arrayClassAdd(caller, &v))
{
return 1;
}
}
}
return 0;
}
ClassFunction(getArrayIdx) {
s64 getVal = (*args)->integer.value;
// Out of bounds
if (getVal < 0 || getVal >= caller->solvedArray.vector.count) {
SCRIPT_FATAL_ERR("Accessing index %d while array is %d long", (int)getVal, (int)caller->solvedArray.vector.count);
}
Variable_t a = arrayClassGetIdx(caller, getVal);
if (a.variableType == None)
return NULL;
return copyVariableToPtr(a);
}
ClassFunction(getArrayLen) {
return newIntVariablePtr(caller->solvedArray.vector.count);
}
ClassFunction(arraySlice) {
s64 skipAmount = getIntValue(*args);
s64 takeAmount = getIntValue(args[1]);
if (caller->solvedArray.vector.count < (skipAmount + takeAmount) || skipAmount < 0 || takeAmount <= 0) {
SCRIPT_FATAL_ERR("Slicing out of range of array with len %d", (int)caller->solvedArray.vector.count);
}
Variable_t refSkip = { .variableType = SolvedArrayReferenceClass };
refSkip.solvedArray.arrayClassReference = caller;
refSkip.solvedArray.offset = skipAmount;
refSkip.solvedArray.len = takeAmount;
addPendingReference(caller);
return copyVariableToPtr(refSkip);
}
// TODO: arrayForEach does not like the new garbage collector
ClassFunction(arrayForEach) {
Vector_t* v = &caller->solvedArray.vector;
Callback_SetVar_t setVar = { .isTopLevel = 1, .varName = (*args)->string.value };
Variable_t* iter = NULL;
iter = copyVariableToPtr(newIntVariable(0));
iter->gcDoNotFree = 1;
runtimeVariableEdit(&setVar, iter);
for (int i = 0; i < v->count; i++) {
*iter = arrayClassGetIdx(caller, i);
iter->gcDoNotFree = 1;
Variable_t* res = genericCallDirect(args[1], NULL, 0);
if (res == NULL) {
if (scriptLastError == SCRIPT_BREAK) {
break;
}
else {
return NULL;
}
}
}
iter->reference = 1;
free(iter);
return &emptyClass;
}
ClassFunction(arrayCopy) {
Vector_t* v = &caller->solvedArray.vector;
Vector_t copiedArray = vecCopy(v);
Variable_t var = { .variableType = caller->variableType, .solvedArray.vector = copiedArray };
return copyVariableToPtr(var);
}
ClassFunction(arraySet) {
s64 idx = getIntValue(*args);
Vector_t* v = &caller->solvedArray.vector;
if (v->count < idx || idx < 0) {
SCRIPT_FATAL_ERR("Accessing index %d while array is %d long", (int)idx, (int)caller->solvedArray.vector.count);
}
u32 oldCount = caller->solvedArray.vector.count;
caller->solvedArray.vector.count = idx;
if (arrayClassAdd(caller, args[1])){
SCRIPT_FATAL_ERR("Adding the wrong type to a typed array");
}
caller->solvedArray.vector.count = oldCount;
return &emptyClass;
}
ClassFunction(arrayAdd) {
Variable_t* arg = *args;
if (caller->readOnly) {
SCRIPT_FATAL_ERR("Array is read-only");
}
if (arrayClassAdd(caller, arg)){
SCRIPT_FATAL_ERR("Adding the wrong type to a typed array");
}
return &emptyClass;
}
ClassFunction(arrayAddRange) {
Variable_t* arg = *args;
if (caller->readOnly) {
SCRIPT_FATAL_ERR("Array is read-only");
}
if (arrayClassAddRange(caller, arg)) {
SCRIPT_FATAL_ERR("Adding the wrong type to a typed array");
}
return &emptyClass;
}
ClassFunction(arrayContains) {
Vector_t* v = &caller->solvedArray.vector;
Variable_t* arg = *args;
for (int i = 0; i < v->count; i++) {
Variable_t iter = arrayClassGetIdx(caller, i);
if (iter.variableType != arg->variableType){
SCRIPT_FATAL_ERR("type of contains does not match");
}
if (caller->variableType == StringArrayClass) {
if (!strcmp(arg->string.value, iter.string.value))
return newIntVariablePtr(i + 1);
}
else {
if (arg->integer.value == iter.integer.value)
return newIntVariablePtr(i + 1);
}
}
return newIntVariablePtr(0);
}
ClassFunction(arrayMinus) {
s64 count = getIntValue(*args);
Vector_t* v = &caller->solvedArray.vector;
if (v->count < count || count <= 0) {
SCRIPT_FATAL_ERR("Accessing index %d while array is %d long", (int)count, (int)caller->solvedArray.vector.count);
}
if (caller->variableType == StringArrayClass) {
char** arr = v->data;
for (int i = v->count - count; i < count; i++) {
FREE(arr[i]);
}
}
v->count -= count;
return &emptyClass;
}
ClassFunction(bytesToStr) {
if (caller->variableType != ByteArrayClass) {
SCRIPT_FATAL_ERR("Need a bytearray to convert to str");
}
char* buff = malloc(caller->solvedArray.vector.count + 1);
memcpy(buff, caller->solvedArray.vector.data, caller->solvedArray.vector.count);
buff[caller->solvedArray.vector.count] = '\0';
return newStringVariablePtr(buff, 0, 0);
}
ClassFunction(eqArray){
Variable_t *arg = (*args);
if (caller->solvedArray.vector.count != arg->solvedArray.vector.count || arg->variableType != caller->variableType){
return newIntVariablePtr(0);
}
s64 res = memcmp(caller->solvedArray.vector.data, arg->solvedArray.vector.data, caller->solvedArray.vector.count * caller->solvedArray.vector.elemSz);
return newIntVariablePtr(!res);
}
ClassFunction(arrayFind){
Variable_t *arg = (*args);
if (caller->solvedArray.vector.count <= arg->solvedArray.vector.count || arg->variableType != caller->variableType){
return newIntVariablePtr(-1);
}
u8 step = (arg->variableType == ByteArrayClass) ? 1 : 8;
char *haystack = caller->solvedArray.vector.data;
void *needle = arg->solvedArray.vector.data;
for (int i = 0; i < caller->solvedArray.vector.count - arg->solvedArray.vector.count; i++){
if (!memcmp(haystack + (i * step), needle, step * arg->solvedArray.vector.count)){
return newIntVariablePtr(i);
}
}
return newIntVariablePtr(-1);
}
ClassFunctionTableEntry_t arrayFunctions[] = {
{"get", getArrayIdx, 1, anotherOneIntArg },
{"len", getArrayLen, 0, 0},
{"slice", arraySlice, 2, doubleInt},
{"foreach", arrayForEach, 2, oneStringoneFunction},
{"copy", arrayCopy, 0, 0},
{"set", arraySet, 2, oneIntOneAny},
{"+", arrayAdd, 1, anotherAnotherOneVarArg},
{"add", arrayAdd, 1, anotherAnotherOneVarArg},
{"addrange", arrayAddRange, 1, anotherAnotherOneVarArg},
{"-", arrayMinus, 1, anotherOneIntArg},
{"contains", arrayContains, 1, anotherAnotherOneVarArg},
{"bytestostr", bytesToStr, 0, 0},
{"==", eqArray, 1, oneByteArrayClass},
{"==", eqArray, 1, oneIntArrayClass},
{"find", arrayFind, 1, oneByteArrayClass},
{"find", arrayFind, 1, oneIntArrayClass},
};
Variable_t getArrayMember(Variable_t* var, char* memberName) {
return getGenericFunctionMember(var, memberName, arrayFunctions, ARRAY_SIZE(arrayFunctions));
}