#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 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)); }