diff --git a/.gitignore b/.gitignore index 2a385fc..41dc2e1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,8 @@ loader/payload_00.h loader/payload_01.h +source/script/Debug +source/script/*.te +source/script/.vs + *.exe diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 8cbcbee..dc9caca 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -11,11 +11,12 @@ #include #include "../../utils/utils.h" #include "../../keys/nca.h" -#include "../../script/lexer.h" -#include "../../script/parser.h" -#include "../../script/variables.h" #include #include "../../storage/emummc.h" +#include "../../script/eval.h" +#include "../../script/parser.h" +#include "../../script/garbageCollector.h" + MenuEntry_t FileMenuEntries[] = { {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "-- File menu --"}, @@ -79,10 +80,11 @@ void RunScript(char *path, FSEntry_t entry){ if (!script) return; - if (((entry.size >= 64 && entry.sizeDef == 1) || entry.sizeDef >= 2) && !TConf.minervaEnabled) + if (((entry.size >= 16 && entry.sizeDef == 1) || entry.sizeDef >= 2) && !TConf.minervaEnabled) return; gfx_clearscreen(); + /* scriptCtx_t ctx = createScriptCtx(); ctx.script = runLexer(script, size); free(script); @@ -94,6 +96,30 @@ void RunScript(char *path, FSEntry_t entry){ freeDictVector(&ctx.varDict); lexarVectorClear(&ctx.script); + */ + + gfx_printf("Init gc\n"); + initGarbageCollector(); + gfx_printf("Parsing\n"); + ParserRet_t ret = parseScript(script); + free(script); + gfx_printf("Init vars\n"); + setStaticVars(&ret.staticVarHolder); + initRuntimeVars(); + + gfx_printf("start script\n"); + Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); + + exitRuntimeVars(); + exitGarbageCollector(); + exitStaticVars(&ret.staticVarHolder); + exitFunction(ret.main.operations.data, ret.main.operations.count); + vecFree(ret.staticVarHolder); + vecFree(ret.main.operations); + + hidWait(); + hidWait(); + hidWait(); } void RenameFile(char *path, FSEntry_t entry){ diff --git a/source/fs/menus/foldermenu.c b/source/fs/menus/foldermenu.c index 1d8b4d3..74325a5 100644 --- a/source/fs/menus/foldermenu.c +++ b/source/fs/menus/foldermenu.c @@ -11,9 +11,6 @@ #include #include "../../utils/utils.h" #include "../../keys/nca.h" -#include "../../script/lexer.h" -#include "../../script/parser.h" -#include "../../script/variables.h" #include #include "../fscopy.h" diff --git a/source/main.c b/source/main.c index 78c8507..1c9288b 100644 --- a/source/main.c +++ b/source/main.c @@ -308,8 +308,8 @@ void ipl_main() if (res == 0) hidWait(); - if (FileExists("sd:/startup.te")) - RunScript("sd:/", newFSEntry("startup.te")); + //if (FileExists("sd:/startup.te")) + // RunScript("sd:/", newFSEntry("startup.te")); EnterMainMenu(); diff --git a/source/script/ABadIdeaVersion3.c b/source/script/ABadIdeaVersion3.c new file mode 100644 index 0000000..5a52ce9 --- /dev/null +++ b/source/script/ABadIdeaVersion3.c @@ -0,0 +1,91 @@ +#ifdef WIN32 + +#include +#include "compat.h" +#include "parser.h" +#include "intClass.h" +#include "StringClass.h" +#include "eval.h" +#include "garbageCollector.h" + +// TODO: error handling DONE +// TODO: unsolved arrays +// TODO: free-ing vars & script at end +// TODO: implement functions from tsv2 +// TODO: add len to string +// TODO: clear old int values from array DONE +// TODO: int and str should be statically included in OP_t DONE + +char* readFile(char* path) { + FILE* fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + + fseek(fp, 0L, SEEK_END); + size_t size = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + char* ret = calloc(size + 1, 1); + fread(ret, size, 1, fp); + + fclose(fp); + return ret; +} + +int main() +{ + //gfx_printf("Hello world!\n"); + + //StartParse("a b c de 0x1 0x10 \"yeet\" + + "); + /* + Variable_t b = newStringVariable("Hello world\n", 1, 0); + callClass("__print__", &b, NULL, NULL); + + Variable_t a = newIntVariable(69, 0); + Variable_t c = newIntVariable(1, 0); + Variable_t e = newStringVariable("snake", 1, 0); + Vector_t fuk = newVec(sizeof(Variable_t), 1); + vecAdd(&fuk, c); + Variable_t *d = callClass("+", &a, NULL, &fuk); + callClass("__print__", d, NULL, NULL); + */ + /* + Vector_t v = newVec(sizeof(int), 4); + int a = 69; + vecAdd(&v, a); + vecAdd(&v, a); + vecAdd(&v, a); + vecAdd(&v, a); + + vecForEach(int*, b, (&v)) + printf("%d\n", *b); + + return; + */ + + initGarbageCollector(); + + char* script = readFile("input.te"); + if (script == NULL) + return; + + //parseScript("#REQUIRE VER 3.0.5\nmain = { two = 1 + 1 }"); + //ParserRet_t ret = parseScript("a.b.c(1){ a.b.c() }"); + ParserRet_t ret = parseScript(script); + free(script); + + setStaticVars(&ret.staticVarHolder); + initRuntimeVars(); + + Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); + + exitRuntimeVars(); + exitGarbageCollector(); + exitStaticVars(&ret.staticVarHolder); + exitFunction(ret.main.operations.data, ret.main.operations.count); + vecFree(ret.staticVarHolder); + vecFree(ret.main.operations); + + gfx_printf("done"); +} +#endif \ No newline at end of file diff --git a/source/script/ABadIdeaVersion3.vcxproj b/source/script/ABadIdeaVersion3.vcxproj new file mode 100644 index 0000000..c34bbfa --- /dev/null +++ b/source/script/ABadIdeaVersion3.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {b4ea4793-03fc-4c25-b69b-a5fbad2d89d5} + ABadIdeaVersion3 + 10.0 + + + + Application + true + v142 + Unicode + false + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + ProgramDatabase + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MinSpace + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/script/ABadIdeaVersion3.vcxproj.filters b/source/script/ABadIdeaVersion3.vcxproj.filters new file mode 100644 index 0000000..490e559 --- /dev/null +++ b/source/script/ABadIdeaVersion3.vcxproj.filters @@ -0,0 +1,135 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {c245ac36-a649-432b-a663-98ff9d02d3f4} + + + {e4d90dab-a1e0-4a27-82a1-dc2c6b81f0bd} + + + {1aacfe02-949c-4394-b408-28d73d702918} + + + {5878f4a8-cac0-40aa-8866-6109bf6688ab} + + + {ec7391f8-d60e-46eb-965e-c2d84d48d784} + + + {015ca379-a813-4d13-a929-3b0efe72bb02} + + + {64738969-63b9-4d0e-85b9-d9a63a7e36b3} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Classes\Generic + + + Source Files + + + Source Files\Classes\Function + + + Source Files\Classes\String + + + Source Files\Classes\Array + + + Source Files\Classes\Array + + + Source Files\Classes\Int + + + Source Files\Classes\Array + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Source Files\Classes\Dictionary + + + Source Files\Classes\Array + + + Source Files\Classes\Int + + + Source Files\Classes\String + + + Source Files\Classes\Array + + + Source Files\Classes\Function + + + Source Files\Classes\Generic + + + Source Files\Classes\Array + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/source/script/ABadIdeaVersion3.vcxproj.user b/source/script/ABadIdeaVersion3.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/source/script/ABadIdeaVersion3.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/script/StringClass.c b/source/script/StringClass.c new file mode 100644 index 0000000..1de459e --- /dev/null +++ b/source/script/StringClass.c @@ -0,0 +1,60 @@ +#include "StringClass.h" +#include "compat.h" +#include "intClass.h" +#include + +char* getStringValue(Variable_t* var) { + if (var->variableType != StringClass) + return NULL; + + return var->string.value; +} + +// Will NOT copy the string, the pointer is taken as-is +StringClass_t createStringClass(char* in, u8 free) { + StringClass_t a = { 0 }; + a.free = free; + a.value = in; + return a; +} + +Variable_t newStringVariable(char *x, u8 readOnly, u8 freeOnExit) { + Variable_t var = { .variableType = StringClass, .readOnly = readOnly, .string = createStringClass(x, freeOnExit) }; + return var; +} + +ClassFunction(printStringVariable) { + if (caller->variableType == StringClass) { + StringClass_t* a = &caller->string; + gfx_printf("%s", a->value); + } + return &emptyClass; +} + +ClassFunction(addStringVariables) { + char* s1 = getStringValue(caller); + char* s2 = getStringValue(*args); + + char* n = malloc(strlen(s1) + strlen(s2) + 1); + strcpy(n, s1); + strcat(n, s2); + + return newStringVariablePtr(n, 0, 1); +} + +ClassFunction(getStringLength) { + char* s1 = getStringValue(caller); + return newIntVariablePtr(strlen(s1)); +} + +u8 oneStringArg[] = { StringClass }; + +ClassFunctionTableEntry_t stringFunctions[] = { + {"print", printStringVariable, 0, 0}, + {"+", addStringVariables, 1, oneStringArg }, + {"len", getStringLength, 0, 0}, +}; + +Variable_t getStringMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, stringFunctions, ARRAY_SIZE(stringFunctions)); +} \ No newline at end of file diff --git a/source/script/StringClass.h b/source/script/StringClass.h new file mode 100644 index 0000000..f712de0 --- /dev/null +++ b/source/script/StringClass.h @@ -0,0 +1,10 @@ +#pragma once +#include "model.h" +#include "genericClass.h" + +StringClass_t createStringClass(char* in, u8 free); +char* getStringValue(Variable_t* var); + +Variable_t newStringVariable(char *x, u8 readOnly, u8 freeOnExit); +#define newStringVariablePtr(x, readOnly, freeOnExit) copyVariableToPtr(newStringVariable(x, readOnly, freeOnExit)) +Variable_t getStringMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/args.c b/source/script/args.c deleted file mode 100644 index ff53131..0000000 --- a/source/script/args.c +++ /dev/null @@ -1,502 +0,0 @@ -#include "args.h" -#include "types.h" -#include "functions.h" -#include "variables.h" -#include -#include -#include "../utils/utils.h" - -char* utils_copyStringSize(const char* in, int size) { - if (size > strlen(in) || size < 0) - size = strlen(in); - - char* out = calloc(size + 1, 1); - //strncpy(out, in, size); - if (size) - memcpy(out, in, size); - return out; -} - -// do not include first openToken! -int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken) { - int i = 0; - int layer = 0; - for (; i < len; i++) { - if (tokens[i].token == openToken) - layer++; - else if (tokens[i].token == closeToken) { - if (layer == 0) - return i; - layer--; - } - } - - return -1; -} - -Vector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len) { - Vector_t args = newVec(sizeof(Variable_t), 5); - int lastLoc = 0; - for (int i = 0; i < len; i++) { - if (tokens[i].token == LSBracket) { - int distance = distanceBetweenTokens(&tokens[i + 1], len - i - 1, LSBracket, RSBracket); - i += distance + 1; - } - if (tokens[i].token == LBracket){ - int distance = distanceBetweenTokens(&tokens[i + 1], len - i - 1, LBracket, RBracket); - i += distance + 1; - } - if (tokens[i].token == Seperator) { - Variable_t res = solveEquation(ctx, &tokens[lastLoc], i - lastLoc, 0); - lastLoc = i + 1; - - vecAddElement(&args, res); - } - - if (i + 1 >= len) { - Variable_t res = solveEquation(ctx, &tokens[lastLoc], i + 1 - lastLoc, 0); - vecAddElement(&args, res); - } - } - - return args; -} - -#define ErrValue(err) (Variable_t) {.varType = ErrType, .integerType = err} -#define IntValue(i) (Variable_t) {.varType = IntType, .integerType = i} -#define StrValue(s) (Variable_t) {.varType = StringType, .stringType = s} - -#define ELIFTX(x) else if (tokens[i].token == x) - -Variable_t getVarFromToken(scriptCtx_t* ctx, lexarToken_t* tokens, int* index, u32 maxLen) { - Variable_t val = { 0 }; - int i = *index; - - if (tokens[i].token == Variable) { - Variable_t* var = dictVectorFind(&ctx->varDict, tokens[i].text); - if (var != NULL) { - val = *var; - val.free = 0; - } - else { - val = ErrValue(ERRNOVAR); - } - } - ELIFTX(IntLit) { - val = IntValue(tokens[i].val); - } - ELIFTX(StrLit) { - val = StrValue(tokens[i].text); - val.free = 0; - } - ELIFTX(ArrayVariable) { - Variable_t* var = dictVectorFind(&ctx->varDict, tokens[i].text); - i += 2; - - if (var == NULL) - return ErrValue(ERRNOVAR); - - int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LSBracket, RSBracket); - if (argCount < 0) - return ErrValue(ERRSYNTAX); - - Variable_t index = solveEquation(ctx, &tokens[i], argCount, 0); - i += argCount; - - if (index.varType != IntType) - return ErrValue(ERRINVALIDTYPE); - - if (var->vectorType.count <= index.integerType || index.integerType < 0) - return ErrValue(ERRSYNTAX); - - switch (var->varType) { - case StringArrayType: - val = StrValue((vecGetArray(char**, var->vectorType))[index.integerType]); - break; - case IntArrayType: - val = IntValue((vecGetArray(int*, var->vectorType))[index.integerType]); - break; - case ByteArrayType: - val = IntValue((vecGetArray(u8*, var->vectorType))[index.integerType]); - break; - default: - return ErrValue(ERRINVALIDTYPE); - } - } - ELIFTX(Function) { - i += 2; - - int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LBracket, RBracket); - if (argCount < 0) - return ErrValue(ERRSYNTAX); - - val = executeFunction(ctx, tokens[i - 2].text, &tokens[i], argCount); - - i += argCount; - } - ELIFTX(LSBracket) { - i++; - - int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LSBracket, RSBracket); - if (argCount < 0) - return ErrValue(ERRSYNTAX); - - val.varType = EmptyArrayType; - - if (argCount > 0){ - Vector_t arrayVars = extractVars(ctx, &tokens[i], argCount); - Variable_t* variables = vecGetArray(Variable_t*, arrayVars); - int type = variables[0].varType; - if (!(type == StringType || type == IntType)) - return ErrValue(ERRINVALIDTYPE); - - val.varType = (type + 2); - val.free = 1; - val.vectorType = newVec((type == IntType) ? sizeof(int) : sizeof(char*), arrayVars.count); - - for (int j = 0; j < arrayVars.count; j++) { - if (variables[j].varType != type) - return ErrValue(ERRINVALIDTYPE); // Free-ing issue!! - - if (type == StringType) { - char* temp = CpyStr(variables[j].stringType); - vecAddElement(&val.vectorType, temp); - } - else { - vecAddElement(&val.vectorType, variables[j].integerType); - } - } - - i += argCount; - freeVariableVector(&arrayVars); - } - } - ELIFTX(LBracket) { - i++; - int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LBracket, RBracket); - if (argCount < 0) - return ErrValue(ERRSYNTAX); - - val = solveEquation(ctx, &tokens[i], argCount, 0); - i += argCount; - } - else { - // ERR - return ErrValue(ERRSYNTAX); - } - - *index = i; - return val; -} - -int matchTypes(Variable_t d1, Variable_t d2, int type) { - return (d1.varType == d2.varType && d1.varType == type); -} - -#define ELIFT(token) else if (localOpToken == token) - -Variable_t solveEquation(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len, u8 shouldFree) { - Variable_t res = { 0 }; - u8 lastToken = 0; - u8 invertValue = 0; - lexarToken_t* varToken = NULL; - - for (int i = 0; i < len; i++) { - if (tokens[i].token == Not) - invertValue = !invertValue; - - else if (tokens[i].token == ArrayVariableAssignment || tokens[i].token == VariableAssignment) { - varToken = &tokens[i]; - if (tokens[i].token == ArrayVariableAssignment) { - int distance = distanceBetweenTokens(&tokens[i] + 2, len, LSBracket, RSBracket); - i += distance + 2; - } - } - - else if (tokens[i].token >= Variable && tokens[i].token <= LSBracket) { - Variable_t val = getVarFromToken(ctx, tokens, &i, len - i); - - if (val.varType == ErrType) - return val; - - if (val.varType == IntType && invertValue) { - val.integerType = !val.integerType; - } - invertValue = 0; - - if (lastToken) { - u16 localOpToken = lastToken; // do we need local op token? - lastToken = 0; - - if (matchTypes(res, val, IntType)) { - if (localOpToken == Plus) - res.integerType += val.integerType; - ELIFT(Minus) - res.integerType -= val.integerType; - ELIFT(Multiply) - res.integerType *= val.integerType; - ELIFT(Division) { - if (!val.integerType) - res = ErrValue(ERRDIVBYZERO); - else - res.integerType = res.integerType / val.integerType; - } - ELIFT(Mod) - res.integerType %= val.integerType; - ELIFT(Smaller) - res.integerType = res.integerType < val.integerType; - ELIFT(SmallerEqual) - res.integerType = res.integerType <= val.integerType; - ELIFT(Bigger) - res.integerType = res.integerType > val.integerType; - ELIFT(BiggerEqual) - res.integerType = res.integerType >= val.integerType; - ELIFT(EqualEqual) - res.integerType = res.integerType == val.integerType; - ELIFT(NotEqual) - res.integerType = res.integerType != val.integerType; - ELIFT(LogicAND) { - res.integerType = res.integerType && val.integerType; - if (!res.integerType) - break; - } - ELIFT(LogicOR) { - res.integerType = res.integerType || val.integerType; - if (res.integerType) - break; - } - ELIFT(AND) - res.integerType = res.integerType & val.integerType; - ELIFT(OR) - res.integerType = res.integerType | val.integerType; - ELIFT(BitShiftLeft) - res.integerType = res.integerType << val.integerType; - ELIFT(BitShiftRight) - res.integerType = res.integerType >> val.integerType; - else - return ErrValue(ERRBADOPERATOR); - } - else if (matchTypes(res, val, StringType)) { - if (localOpToken == Plus) { - char* buff = calloc(strlen(res.stringType) + strlen(val.stringType) + 1, 1); - strcpy(buff, res.stringType); - strcat(buff, val.stringType); - - if (res.free) free(res.stringType); // we should replace these with variablefree - if (val.free) free(val.stringType); - res.stringType = buff; - res.free = 1; - } - ELIFT(EqualEqual) { - res.typeUnion = IntType; - int compRes = !strcmp(res.stringType, val.stringType); - if (res.free) free(res.stringType); - if (val.free) free(val.stringType); - res.integerType = compRes; - res.free = 0; - } - ELIFT(Minus) { - u32 lenRes = strlen(res.stringType); - u32 valRes = strlen(val.stringType); - if (!strcmp(res.stringType + lenRes - valRes, val.stringType)) { - char *temp = malloc(lenRes - valRes + 1); - memcpy(temp, res.stringType, lenRes - valRes); - temp[lenRes - valRes] = 0; - freeVariable(res); - res.free = 1; - res.stringType = temp; - } - - freeVariable(val); - } - ELIFT(Division) { - int valLen = strlen(val.stringType); - if (!valLen) { - res = ErrValue(ERRSYNTAX); - continue; - } - - char* start = res.stringType; - char* find = NULL; - Vector_t arr = newVec(sizeof(char**), 10); - char* temp; - - while ((find = (strstr(start, val.stringType))) != NULL) { - temp = utils_copyStringSize(start, find - start); - vecAddElement(&arr, temp); - - start = find + valLen; - } - - temp = utils_copyStringSize(start, res.stringType + strlen(res.stringType) - start); - vecAddElement(&arr, temp); - if (res.free) free(res.stringType); // do we free here? - if (val.free) free(val.stringType); - - res.varType = StringArrayType; - res.free = 1; - res.vectorType = arr; - } - else - return ErrValue(ERRBADOPERATOR); - } - else if ((res.varType == IntArrayType || res.varType == ByteArrayType) && val.varType == IntType) { - if (localOpToken == Plus) { - Vector_t newV = vecCopy(&res.vectorType); - freeVariable(res); - res.vectorType = newV; - res.free = 1; - if (res.varType == IntArrayType) - vecAddElement(&res.vectorType, val.integerType); - else { - u8 in = ((u8)val.integerType & 0xFF); - vecAddElement(&res.vectorType, in); - } - } - ELIFT(Minus){ - if (val.integerType >= res.vectorType.count) - return ErrValue(ERRSYNTAX); - - res.vectorType.count -= val.integerType; - Vector_t newV = vecCopy(&res.vectorType); - freeVariable(res); - res.vectorType = newV; - res.free = 1; - } - ELIFT(Selector){ - if (val.integerType >= res.vectorType.count) - return ErrValue(ERRSYNTAX); - - Vector_t newV = vecCopyOffset(&res.vectorType, val.integerType); - freeVariable(res); - res.vectorType = newV; - res.free = 1; - } - } - else if (res.varType == StringType && val.varType == IntType){ - if (localOpToken == Minus){ - u32 resLen = strlen(res.stringType); - if (resLen < val.integerType) - return ErrValue(ERRSYNTAX); - - char *temp = utils_copyStringSize(res.stringType, resLen - val.integerType); - - freeVariable(res); - res.stringType = temp; - res.free = 1; - } - ELIFT(Selector){ - u32 resLen = strlen(res.stringType); - if (resLen < val.integerType) - return ErrValue(ERRSYNTAX); - - char *temp = CpyStr(res.stringType + val.integerType); - - freeVariable(res); - res.stringType = temp; - res.free = 1; - } - else - return ErrValue(ERRBADOPERATOR); - } - else if (res.varType == EmptyArrayType && localOpToken == Plus){ - res.free = 1; - res.varType = val.varType + 2; - - if (val.varType == IntType){ - res.vectorType = newVec(sizeof(int), 4); - vecAddElem(&res.vectorType, val.integerType); - } - else if (val.varType == StringType) { - res.vectorType = newVec(sizeof(char*), 4); - char *temp = CpyStr(val.stringType); - vecAddElem(&res.vectorType, temp); - } - else - return ErrValue(ERRBADOPERATOR); - - freeVariable(val); - } - else if (res.varType == StringArrayType && val.varType == StringType){ - if (localOpToken == Plus){ - Vector_t new = vecCopy(&res.vectorType); - vecDefArray(char **, strings, new); - for (int j = 0; j < new.count; j++){ - strings[j] = CpyStr(strings[j]); - } - - freeVariable(res); - - char *temp = CpyStr(val.stringType); - vecAddElem(&new, temp); - - res.free = 1; - res.vectorType = new; - } - else - return ErrValue(ERRBADOPERATOR); - } - else - return ErrValue(ERRBADOPERATOR); - } - else { - res = val; - } - } - else if (tokens[i].token >= Plus && tokens[i].token <= BitShiftRight) { - lastToken = tokens[i].token; - } - } - - if (varToken != NULL) { - if (varToken->token == VariableAssignment) { - dict_t newVar = newDict(CpyStr(varToken->text), res); - dictVectorAdd(&ctx->varDict, newVar); - } - else { - Variable_t* var = dictVectorFind(&ctx->varDict, varToken->text); - if (var != NULL) { - if (var->varType - 2 == res.varType || (var->varType == ByteArrayType && res.varType == IntType)) { - int distance = distanceBetweenTokens(varToken + 2, len, LSBracket, RSBracket); - if (distance < 0) { - // ERR - return ErrValue(ERRSYNTAX); - } - Variable_t index = solveEquation(ctx, varToken + 2, distance, 0); - if (index.varType != IntType) { - // ERR - } - else if (index.integerType < 0 || var->vectorType.count <= index.integerType) { - // ERR - } - else { - if (var->varType == IntArrayType) { - int* arr = vecGetArray(int*, var->vectorType); - arr[index.integerType] = res.integerType; - } - else if (var->varType == StringArrayType) { - char** arr = vecGetArray(char**, var->vectorType); - arr[index.integerType] = CpyStr(res.stringType); - } - else if (var->varType == ByteArrayType) { - u8* arr = vecGetArray(u8*, var->vectorType); - arr[index.integerType] = res.integerType & 0xFF; - } - } - } - else { - // ERR - } - } - else { - //ERR - } - } - } - else { - if (shouldFree) // we should get rid of this ugly free. why not set .free to 0 when assigning it then free in parser.c? - freeVariable(res); - } - - return res; -} \ No newline at end of file diff --git a/source/script/args.h b/source/script/args.h deleted file mode 100644 index d900961..0000000 --- a/source/script/args.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "types.h" - -char* utils_copyStringSize(const char* in, int size); -Variable_t solveEquation(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len, u8 shouldFree); -int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken); -Vector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len); \ No newline at end of file diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c new file mode 100644 index 0000000..14be54f --- /dev/null +++ b/source/script/arrayClass.c @@ -0,0 +1,259 @@ +#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 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 }; +} + +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(createRefSkip) { + s64 skipAmount = getIntValue(*args); + if (caller->solvedArray.vector.count < skipAmount || skipAmount <= 0) { + SCRIPT_FATAL_ERR("Accessing index %d while array is %d long", (int)skipAmount, (int)caller->solvedArray.vector.count); + } + + Variable_t refSkip = { .variableType = SolvedArrayReferenceClass }; + refSkip.solvedArray.arrayClassReference = caller; + refSkip.solvedArray.offset = skipAmount; + refSkip.solvedArray.len = caller->solvedArray.vector.count - skipAmount; + addPendingReference(caller); + return copyVariableToPtr(refSkip); +} + + +ClassFunction(takeArray) { + s64 skipAmount = getIntValue(*args); + if (caller->solvedArray.vector.count < skipAmount || skipAmount <= 0) { + SCRIPT_FATAL_ERR("Accessing index %d while array is %d long", (int)skipAmount, (int)caller->solvedArray.vector.count); + } + + Variable_t refSkip = { .variableType = SolvedArrayReferenceClass }; + refSkip.solvedArray.arrayClassReference = caller; + refSkip.solvedArray.len = skipAmount; + addPendingReference(caller); + return copyVariableToPtr(refSkip); +} + + +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)); + + runtimeVariableEdit(&setVar, iter); + + for (int i = 0; i < v->count; i++) { + *iter = arrayClassGetIdx(caller, i); + + Variable_t* res = genericCallDirect(args[1], NULL, 0); + if (res == NULL) + return NULL; + } + + 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); + } + + if (caller->readOnly) { + SCRIPT_FATAL_ERR("Array is read-only"); + } + + if (caller->variableType == IntArrayClass) { + if (args[1]->variableType != IntClass) { + return NULL; // TODO: add proper error handling + } + + s64* a = v->data; + a[idx] = getIntValue(args[1]); + } + else if (caller->variableType == StringArrayClass) { + if (args[1]->variableType != StringClass) { + return NULL; // TODO: add proper error handling + } + + char** a = v->data; + FREE(a[idx]); + a[idx] = CpyStr(args[1]->string.value); + } + else if (caller->variableType == ByteArrayClass) { + if (args[1]->variableType != IntClass) { + return NULL; // TODO: add proper error handling + } + + u8* a = v->data; + a[idx] = (u8)(getIntValue(args[1]) & 0xFF); + } + + return &emptyClass; +} + +ClassFunction(arrayAdd) { + Variable_t* arg = *args; + + if (caller->variableType == IntArrayClass) { + if (arg->variableType != IntClass) { + return NULL; // TODO: add proper error handling + } + + vecAdd(&caller->solvedArray.vector, arg->integer.value); + } + else if (caller->variableType == StringArrayClass) { + if (arg->variableType != StringClass) { + return NULL; // TODO: add proper error handling + } + + char* str = CpyStr(arg->string.value); + vecAdd(&caller->solvedArray.vector, str); + } + else if (caller->variableType == ByteArrayClass) { + if (arg->variableType != IntClass) { + return NULL; // TODO: add proper error handling + } + + u8 val = (u8)(arg->integer.value & 0xFF); + vecAdd(&caller->solvedArray.vector, val); + } + + 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 (caller->variableType == StringArrayClass) { + if (!strcmp(arg->string.value, iter.string.value)) + return newIntVariablePtr(1); + } + else { + if (arg->integer.value == iter.integer.value) + return newIntVariablePtr(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("Nedd 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); +} + +ClassFunctionTableEntry_t arrayFunctions[] = { + {"get", getArrayIdx, 1, anotherOneIntArg }, + {"len", getArrayLen, 0, 0}, + {"skip", createRefSkip, 1, anotherOneIntArg}, + {"foreach", arrayForEach, 2, oneStringoneFunction}, + {"copy", arrayCopy, 0, 0}, + {"set", arraySet, 2, oneIntOneAny}, + {"+", arrayAdd, 1, anotherAnotherOneVarArg}, + {"-", arrayMinus, 1, anotherOneIntArg}, + {"take", takeArray, 1, anotherOneIntArg}, + {"contains", arrayContains, 1, anotherAnotherOneVarArg}, + {"bytestostr", bytesToStr, 0, 0}, + {"==", eqArray, 1, oneByteArrayClass}, + {"==", eqArray, 1, oneIntArrayClass}, +}; + +Variable_t getArrayMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, arrayFunctions, ARRAY_SIZE(arrayFunctions)); +} \ No newline at end of file diff --git a/source/script/arrayClass.h b/source/script/arrayClass.h new file mode 100644 index 0000000..733852d --- /dev/null +++ b/source/script/arrayClass.h @@ -0,0 +1,5 @@ +#pragma once +#include "model.h" +#include "genericClass.h" + +Variable_t getArrayMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/arrayReferenceClass.c b/source/script/arrayReferenceClass.c new file mode 100644 index 0000000..2a75e95 --- /dev/null +++ b/source/script/arrayReferenceClass.c @@ -0,0 +1,24 @@ +#include "model.h" +#include "compat.h" +#include "genericClass.h" +#include "intClass.h" +#include "arrayReferenceClass.h" + + +ClassFunction(projectArray) { + Variable_t newArray = { .variableType = caller->solvedArray.arrayClassReference->variableType, .reference = 1, .readOnly = 1 }; + + newArray.solvedArray.vector = caller->solvedArray.arrayClassReference->solvedArray.vector; + newArray.solvedArray.vector.data = (u8*)caller->solvedArray.arrayClassReference->solvedArray.vector.data + (caller->solvedArray.offset * caller->solvedArray.arrayClassReference->solvedArray.vector.elemSz); + newArray.solvedArray.vector.count = caller->solvedArray.len; + + return copyVariableToPtr(newArray); +} + +ClassFunctionTableEntry_t arrayReferenceFunctions[] = { + {"project", projectArray, 0, 0}, +}; + +Variable_t getArrayReferenceMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, arrayReferenceFunctions, ARRAY_SIZE(arrayReferenceFunctions)); +} \ No newline at end of file diff --git a/source/script/arrayReferenceClass.h b/source/script/arrayReferenceClass.h new file mode 100644 index 0000000..c3287d8 --- /dev/null +++ b/source/script/arrayReferenceClass.h @@ -0,0 +1,5 @@ +#pragma once +#include "model.h" +#include "genericClass.h" + +Variable_t getArrayReferenceMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/compat.h b/source/script/compat.h new file mode 100644 index 0000000..63eebf3 --- /dev/null +++ b/source/script/compat.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef WIN32 + #include + #include +#define gfx_printf(str, ...) printf(str, ##__VA_ARGS__) + #define gfx_vprintf(str, va) vprintf(str, va); + #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + #define LP_VER_MJ 3 + #define LP_VER_MN 0 + #define LP_VER_BF 5 + #define FREE(x) if (x) free(x) + #define CpyStr(x) _strdup(x); + #include "vector.h" + #pragma _CRT_SECURE_NO_WARNINGS +#else + #include "../gfx/gfx.h" + #include + #include "../utils/vector.h" + #include "../utils/utils.h" +#endif \ No newline at end of file diff --git a/source/script/dictionaryClass.h b/source/script/dictionaryClass.h new file mode 100644 index 0000000..665b57c --- /dev/null +++ b/source/script/dictionaryClass.h @@ -0,0 +1,3 @@ +#pragma once +#include "model.h" +#include "genericClass.h" diff --git a/source/script/eval.c b/source/script/eval.c new file mode 100644 index 0000000..747a2e2 --- /dev/null +++ b/source/script/eval.c @@ -0,0 +1,266 @@ +#include "model.h" +#include "compat.h" +#include "genericClass.h" +#include "eval.h" +#include "garbageCollector.h" +#include "standardLibrary.h" +#include "scriptError.h" +#include "StringClass.h" +#include "intClass.h" +#include "unsolvedArrayClass.h" +#include "functionClass.h" +#include + +Variable_t* staticVars; + +void setStaticVars(Vector_t* vec) { + staticVars = vec->data; +} + +Vector_t runtimeVars; + +void initRuntimeVars() { + runtimeVars = newVec(sizeof(Dict_t), 8); +} + +void exitRuntimeVars() { + vecForEach(Dict_t*, runtimeVar, (&runtimeVars)) { + FREE(runtimeVar->name); + removePendingReference(runtimeVar->var); + } + + vecFree(runtimeVars); +} + +Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback) { + Variable_t* var = NULL; + CallArgs_t* args = NULL; + + if ((op + 1)->token == CallArgs) + args = &(op + 1)->callArgs; + + if (op->token == BetweenBrackets) { + var = eval(op->variable.betweenBrackets.data, op->variable.betweenBrackets.len, 1); + } + else if (op->token == Variable) { + if (op->variable.staticVariableSet) { + if (op->variable.staticVariableRef) { + op->variable.staticVariable = &staticVars[(int)op->variable.staticVariable]; + op->variable.staticVariableRef = 0; + op->variable.staticVariable->readOnly = 1; + op->variable.staticVariable->reference = 1; + op->variable.staticVariable->gcDoNotFree = 1; + } + + var = op->variable.staticVariable; + + if (var->variableType == UnresolvedArrayClass) { + var = solveArray(var); + } + } + else if (op->variable.staticVariableType > 0) { + if (op->variable.staticVariableType == 1) { + var = copyVariableToPtr(newIntVariable(op->variable.integerType)); + } + else if (op->variable.staticVariableType == 2) { + var = copyVariableToPtr(newStringVariable(op->variable.stringType, 1, 0)); + var->reference = 1; + } + else if (op->variable.staticVariableType == 3) { + var = copyVariableToPtr(newFunctionVariable(createFunctionClass((Function_t) { 0 }, op->variable.staticFunction))); + var->reference = 1; + } + } + else { + if (args != NULL) { + if (args->action == ActionSet && args->extraAction == ActionExtraNone) { + setCallback->isTopLevel = 1; + setCallback->varName = op->variable.name; + setCallback->hasVarName = 1; + return NULL; + } + } + + vecForEach(Dict_t*, variableArrayEntry, (&runtimeVars)) { + if (!strcmp(variableArrayEntry->name, op->variable.name)) { + var = variableArrayEntry->var; + break; + } + } + + if (var == NULL) { + SCRIPT_FATAL_ERR("Variable '%s' not found", op->variable.name); + } + + addPendingReference(var); + } + } + + while (args) { + Variable_t* varNext = NULL; + if (args->action == ActionGet) { + if (args->extraAction == ActionExtraMemberName && args->next != NULL && args->next->action == ActionCall) { + varNext = callMemberFunction(var, args->extra, args->next); + args = args->next; + } + else { + varNext = genericGet(var, args); + } + } + else if (args->action == ActionSet) { + if (var->readOnly) { + SCRIPT_FATAL_ERR("Variable which set was called on is read-only"); + return NULL; + } + + if (args->extraAction == ActionExtraMemberName || args->extraAction == ActionExtraArrayIndex) { + setCallback->hasVarName = (args->extraAction == ActionExtraMemberName) ? 1 : 0; + setCallback->setVar = var; + if (args->extraAction == ActionExtraMemberName) { + setCallback->varName = args->extra; + } + else { + setCallback->idxVar = args->extra; + } + } + else { + SCRIPT_FATAL_ERR("[FATAL] Unexpected set!"); + } + return NULL; + } + else if (args->action == ActionCall) { + varNext = genericCall(var, args); + } + + if (varNext == NULL) + return NULL; + + removePendingReference(var); + + //if (!var->reference) + // freeVariable(&var); + + var = varNext; + args = args->next; + } + + if (op->not && var) { + Variable_t* newVar = callMemberFunctionDirect(var, "not", NULL, 0); + removePendingReference(var); + var = newVar; + } + + return var; +} + +void runtimeVariableEdit(Callback_SetVar_t* set, Variable_t* curRes) { + if (set->isTopLevel) { + vecForEach(Dict_t*, variableArrayEntry, (&runtimeVars)) { + if (!strcmp(variableArrayEntry->name, set->varName)) { + removePendingReference(variableArrayEntry->var); + //addPendingReference(curRes); + variableArrayEntry->var = curRes; + return; + } + } + + Dict_t newStoredVariable = { 0 }; + newStoredVariable.name = CpyStr(set->varName); + newStoredVariable.var = curRes; + vecAdd(&runtimeVars, newStoredVariable); + return; + } + + if (set->idxVar) { + Variable_t* var = eval(set->idxVar->operations.data, set->idxVar->operations.count, 1); + Variable_t* args[2] = { var, curRes }; + callMemberFunctionDirect(set->setVar, "set", args, 2); + removePendingReference(var); + } + else { + Variable_t varName = { .variableType = StringClass, .reference = 1, .string.value = set->varName }; + Variable_t* args[2] = { &varName, curRes }; + callMemberFunctionDirect(set->setVar, "set", args, 2); + } + + // TODO: add non-top level sets +} + +Variable_t* eval(Operator_t* ops, u32 len, u8 ret) { + Variable_t* curRes = NULL; + Operator_t* curOp = NULL; + Callback_SetVar_t set = { 0 }; + for (u32 i = 0; i < len; i++) { + Operator_t* cur = &ops[i]; + + if (cur->token == CallArgs) + continue; + + if (cur->token == EquationSeperator) { + scriptCurrentLine = cur->lineNumber; + if (set.hasBeenNoticed == 1) + runtimeVariableEdit(&set, curRes); + else + removePendingReference(curRes); + + memset(&set, 0, sizeof(Callback_SetVar_t)); + curRes = NULL; + curOp = NULL; + continue; + } + + if (curRes == NULL) { + if (cur->token != Variable && cur->token != BetweenBrackets) { + SCRIPT_FATAL_ERR("First token is not a variable"); + } + else { + curRes = opToVar(cur, &set); + if (!curRes) { + if ((set.varName != NULL || set.idxVar != NULL) && set.hasBeenNoticed == 0) { + set.hasBeenNoticed = 1; + continue; + } + return NULL; + } + } + continue; + } + + if (curOp == NULL) { + if (cur->token != Variable && cur->token != BetweenBrackets) { + curOp = cur; + } + else { + SCRIPT_FATAL_ERR("Expected operator"); + } + continue; + } + + Variable_t* rightSide = opToVar(cur, &set); + if (!rightSide) + return NULL; + + + // Issue lies here for freeing issues, curRes is corrupted + Variable_t* result = callMemberFunctionDirect(curRes, curOp->tokenStr, &rightSide, 1); + // Free old values + + removePendingReference(curRes); + removePendingReference(rightSide); + rightSide = NULL; + curOp = NULL; + + curRes = result; + } + + if (set.hasBeenNoticed == 1) { + runtimeVariableEdit(&set, curRes); + return &emptyClass; + } + else if (!ret) { + removePendingReference(curRes); + return &emptyClass; + } + + return curRes; +} \ No newline at end of file diff --git a/source/script/eval.h b/source/script/eval.h new file mode 100644 index 0000000..b64ee76 --- /dev/null +++ b/source/script/eval.h @@ -0,0 +1,19 @@ +#pragma once +#include "model.h" + +typedef struct { + struct { + u8 isTopLevel : 1; + u8 hasBeenNoticed : 1; + u8 hasVarName : 1; + }; + Variable_t* setVar; + char* varName; + Function_t* idxVar; +} Callback_SetVar_t; + +Variable_t* eval(Operator_t* ops, u32 len, u8 ret); +void setStaticVars(Vector_t* vec); +void initRuntimeVars(); +void exitRuntimeVars(); +void runtimeVariableEdit(Callback_SetVar_t* set, Variable_t* curRes); \ No newline at end of file diff --git a/source/script/functionClass.c b/source/script/functionClass.c new file mode 100644 index 0000000..489a7fb --- /dev/null +++ b/source/script/functionClass.c @@ -0,0 +1,67 @@ +#include "functionClass.h" +#include "compat.h" +#include "model.h" +#include + +Function_t* getFunctionValue(Variable_t* var) { + if (var->variableType != FunctionClass) + return NULL; + + FunctionClass_t* a = &var->function; + + if (a->builtIn) + return NULL; + + return &a->function; +} + +Function_t createEmptyFunction() { + Function_t a = { 0 }; + a.operations = newVec(sizeof(Operator_t), 0); + return a; +} + +// Will NOT copy the Function, the pointer is taken as-is. Set as NULL to make it builtin +FunctionClass_t createFunctionClass(Function_t in, ClassFunctionTableEntry_t *builtIn) { + FunctionClass_t a = { 0 }; + if (!builtIn) { + a.function = in; + } + else { + a.builtIn = 1; + a.builtInPtr = builtIn; + a.len = 1; + } + + return a; +} + +FunctionClass_t* creteFunctionClassPtr(Function_t in, ClassFunctionTableEntry_t* builtIn) { + FunctionClass_t* a = malloc(sizeof(FunctionClass_t)); + *a = createFunctionClass(in, builtIn); + return a; +} + +Function_t* createFunctionPtrFromFunction(Function_t in) { + Function_t* f = malloc(sizeof(Function_t)); + *f = in; + return f; +} + +// Functions are always readonly +Variable_t newFunctionVariable(FunctionClass_t func) { + Variable_t var = { .variableType = FunctionClass, .readOnly = 1, .function = func }; + return var; +} + +int countTokens(Function_t *func, u8 toCount) { + Operator_t* ops = func->operations.data; + int count = 0; + for (int i = 0; i < func->operations.count; i++) { + if (ops[i].token == toCount) { + count++; + } + } + + return count; +} \ No newline at end of file diff --git a/source/script/functionClass.h b/source/script/functionClass.h new file mode 100644 index 0000000..5b5467f --- /dev/null +++ b/source/script/functionClass.h @@ -0,0 +1,8 @@ +#pragma once +#include "model.h" + +Function_t createEmptyFunction(); +Function_t* createFunctionPtrFromFunction(Function_t in); +Variable_t newFunctionVariable(FunctionClass_t func); +FunctionClass_t createFunctionClass(Function_t in, ClassFunctionTableEntry_t* builtIn); +int countTokens(Function_t* func, u8 toCount); \ No newline at end of file diff --git a/source/script/functions.c b/source/script/functions.c deleted file mode 100644 index c2b7d75..0000000 --- a/source/script/functions.c +++ /dev/null @@ -1,529 +0,0 @@ -#include "types.h" -#include "args.h" -#include "variables.h" -#include -#include "../gfx/gfx.h" -#include -#include "lexer.h" - -#include -#include "../fs/fsutils.h" -#include "../gfx/gfxutils.h" -#include "../hid/hid.h" -#include -#include "../fs/fscopy.h" -#include "../storage/mountmanager.h" -#include "../storage/emummc.h" -#include "../fs/readers/folderReader.h" -#include "../utils/utils.h" -#include "../keys/keys.h" -#include "../storage/emmcfile.h" -#include "../keys/nca.h" -#include "../keys/save.h" -#include "../tegraexplorer/tconf.h" - -#define scriptFunction(name) Variable_t name(scriptCtx_t *ctx, Variable_t *vars, u32 varLen) - -#define varInt(i) newVar(IntType, 0, i) -#define varStr(s) newVar(StringType, 1, .stringType = s) - -scriptFunction(funcIf) { - setCurIndentInstruction(ctx, (vars[0].integerType == 0), 0, -1); - return NullVar; -} - -scriptFunction(funcPrint) { - for (u32 i = 0; i < varLen; i++) { - if (vars[i].varType == IntType) - gfx_printf("%d", vars[i].integerType); - else if (vars[i].varType == StringType) - gfx_printf("%s", vars[i].stringType); - else if (vars[i].varType == IntArrayType) { - gfx_printf("["); - int* v = vecGetArray(int*, vars[i].vectorType); - for (u32 j = 0; j < vars[i].vectorType.count; j++) - gfx_printf((j + 1 == vars[i].vectorType.count) ? "%d" : "%d, ", v[j]); - gfx_printf("]"); - } - } - - return NullVar; -} - -scriptFunction(funcPrintln) { - funcPrint(ctx, vars, varLen); - gfx_printf("\n"); - return NullVar; -} - -scriptFunction(funcWhile) { - setCurIndentInstruction(ctx, (vars[0].integerType == 0), 0, ctx->startEquation); - - return NullVar; -} - -scriptFunction(funcElse) { - indentInstructor_t* curInstruction = getCurIndentInstruction(ctx); - setCurIndentInstruction(ctx, !curInstruction->skip, 0, -1); - return NullVar; -} - -scriptFunction(funcLen) { - if (vars[0].varType >= IntArrayType && vars[0].varType <= ByteArrayType) - return IntVal(vars[0].vectorType.count); - else if (vars[0].varType == StringType) { - if (vars[0].stringType != NULL) - return IntVal(strlen(vars[0].stringType)); - } - - return ErrVar(ERRINVALIDTYPE); -} - -scriptFunction(funcMakeByteArray){ - u8 *buff = malloc(vars[0].vectorType.count); - vecDefArray(int*, entries, vars[0].vectorType); - for (int i = 0; i < vars[0].vectorType.count; i++) - buff[i] = (u8)(entries[i] & 0xFF); - - Vector_t v = vecFromArray(buff, vars[0].vectorType.count, sizeof(u8)); - return newVar(ByteArrayType, 1, .vectorType = v); -} - -scriptFunction(funcSetPixel){ - u32 color = 0xFF000000 | ((vars[2].integerType & 0xFF) << 16) | ((vars[3].integerType & 0xFF) << 8) | (vars[4].integerType & 0xFF); - gfx_set_pixel_horz(vars[0].integerType, vars[1].integerType, color); - return NullVar; -} - -scriptFunction(funcFileExists){ - return newVar(IntType, 0, FileExists(vars[0].stringType)); -} - -// Args: Str (Path) -scriptFunction(funcReadFile){ - u32 fSize = 0; - u8 *buff = sd_file_read(vars[0].stringType, &fSize); - if (buff == NULL) - return ErrVar(ERRFATALFUNCFAIL); - - Vector_t vec = vecFromArray(buff, fSize, sizeof(u8)); - return newVar(ByteArrayType, 1, .vectorType = vec); -} - -// Args: Str (Path), vector(Byte) (toWrite) -scriptFunction(funcWriteFile){ - return newVar(IntType, 0, sd_save_to_file(vars[1].vectorType.data, vars[1].vectorType.count, vars[0].stringType)); -} - -// Args: vector(Byte) -scriptFunction(funcByteToStr){ - char *str = calloc(vars[0].vectorType.count + 1, 1); - memcpy(str, vars[0].vectorType.data, vars[0].vectorType.count); - return newVar(StringType, 1, .stringType = str); -} - -scriptFunction(funcReturn){ - if (ctx->indentIndex > 0){ - vecDefArray(indentInstructor_t*, instructors, ctx->indentInstructors); - for (int i = ctx->indentIndex - 1; i >= 0; i--){ - indentInstructor_t ins = instructors[i]; - if (ins.active && ins.jump && ins.function){ - ctx->curPos = ins.jumpLoc - 1; - ins.active = 0; - ctx->indentIndex = i; - break; - } - } - } - - return NullVar; -} - -scriptFunction(funcExit){ - return ErrVar(ERRESCSCRIPT); -} - -/* -scriptFunction(funcContinue){ - if (ctx->indentIndex > 0){ - vecDefArray(indentInstructor_t*, instructors, ctx->indentInstructors); - for (int i = ctx->indentIndex - 1; i >= 0; i--){ - indentInstructor_t ins = instructors[i]; - if (ins.active && ins.jump && !ins.function){ - ctx->curPos = ins.jumpLoc - 1; - ins.active = 0; - ctx->indentIndex = i; - break; - } - } - } - - return NullVar; -} -*/ - -// Args: Int, Int -scriptFunction(funcSetPrintPos){ - if (vars[0].integerType > 78 || vars[0].integerType < 0 || vars[1].integerType > 42 || vars[1].integerType < 0) - return ErrVar(ERRFATALFUNCFAIL); - - gfx_con_setpos(vars[0].integerType * 16, vars[1].integerType * 16); - return NullVar; -} - -scriptFunction(funcClearScreen){ - gfx_clearscreen(); - return NullVar; -} - -int validRanges[] = { - 1279, - 719, - 1279, - 719 -}; - -// Args: Int, Int, Int, Int, Int -scriptFunction(funcDrawBox){ - for (int i = 0; i < ARR_LEN(validRanges); i++){ - if (vars[i].integerType > validRanges[i] || vars[i].integerType < 0) - return ErrVar(ERRFATALFUNCFAIL); - } - - gfx_box(vars[0].integerType, vars[1].integerType, vars[2].integerType, vars[3].integerType, vars[4].integerType); - return NullVar; -} - -typedef struct { - char *name; - u32 color; -} ColorCombo_t; - -ColorCombo_t combos[] = { - {"RED", COLOR_RED}, - {"ORANGE", COLOR_ORANGE}, - {"YELLOW", COLOR_YELLOW}, - {"GREEN", COLOR_GREEN}, - {"BLUE", COLOR_BLUE}, - {"VIOLET", COLOR_VIOLET}, - {"GREY", COLOR_GREY}, -}; - -u32 GetColor(char *color){ - for (int i = 0; i < ARR_LEN(combos); i++){ - if (!strcmp(combos[i].name, color)){ - return combos[i].color; - } - } - - return COLOR_WHITE; -} - -// Args: Str -scriptFunction(funcSetColor){ - SETCOLOR(GetColor(vars[0].stringType), COLOR_DEFAULT); - return NullVar; -} - -scriptFunction(funcPause){ - return newVar(IntType, 0, hidWait()->buttons); -} - -// Args: Int -scriptFunction(funcWait){ - u32 timer = get_tmr_ms(); - while (timer + vars[0].integerType > get_tmr_ms()){ - gfx_printf(" \r", (vars[0].integerType - (get_tmr_ms() - timer)) / 1000); - hidRead(); - } - return NullVar; -} - -scriptFunction(funcGetVer){ - int *arr = malloc(3 * sizeof(int)); - arr[0] = LP_VER_MJ; - arr[1] = LP_VER_MN; - arr[2] = LP_VER_BF; - Vector_t res = vecFromArray(arr, 3, sizeof(int)); - return newVar(IntArrayType, 1, .vectorType = res); -} - - -// Args: vec(str), int, (optional) vec(str) -scriptFunction(funcMakeMenu){ - if (varLen == 3 && vars[2].vectorType.count != vars[0].vectorType.count) - return ErrVar(ERRSYNTAX); - - Vector_t menuEntries = newVec(sizeof(MenuEntry_t), vars[0].vectorType.count); - vecDefArray(char**, names, vars[0].vectorType); - char **colors; - if (varLen >= 3) - colors = vecGetArray(char**, vars[2].vectorType); - - int *options; - if (varLen == 4) - options = vecGetArray(int*, vars[3].vectorType); - - for (int i = 0; i < vars[0].vectorType.count; i++){ - u32 color = COLORTORGB(((varLen >= 3) ? GetColor(colors[i]) : COLOR_WHITE)); - MenuEntry_t a = {.optionUnion = color, .name = names[i]}; - - if (varLen == 4){ - a.skip = (options[i] & 1) ? 1 : 0; - a.hide = (options[i] & 2) ? 1 : 0; - } - - vecAddElem(&menuEntries, a); - } - - int res = newMenu(&menuEntries, vars[1].integerType, 78, 10, ENABLEB | ALWAYSREDRAW, menuEntries.count); - vecFree(menuEntries); - return varInt(res); -} - -// Args: Str, Str -scriptFunction(funcCombinePath){ - if (varLen <= 1) - return NullVar; - - for (int i = 0; i < varLen; i++){ - if (vars[i].varType != StringType) - return ErrVar(ERRINVALIDTYPE); - } - - char *res = CpyStr(vars[0].stringType); - - for (int i = 1; i < varLen; i++){ - char *temp = CombinePaths(res, vars[i].stringType); - free(res); - res = temp; - } - - return varStr(res); -} - -// Args: Str -scriptFunction(funcEscFolder){ - return newVar(StringType, 1, .stringType = EscapeFolder(vars[0].stringType)); -} - -// Args: Str, Str -scriptFunction(funcFileMove){ - return varInt(f_rename(vars[0].stringType, vars[1].stringType)); -} - -// Args: Str, Str -scriptFunction(funcFileCopy){ - return varInt(FileCopy(vars[0].stringType, vars[1].stringType, COPY_MODE_PRINT).err); -} - -// Args: Str -scriptFunction(funcMmcConnect){ - int res = 0; - if (!strcmp(vars[0].stringType, "SYSMMC")) - res = connectMMC(MMC_CONN_EMMC); - else if (!strcmp(vars[0].stringType, "EMUMMC") && emu_cfg.enabled) - res = connectMMC(MMC_CONN_EMUMMC); - else - return ErrVar(ERRFATALFUNCFAIL); - - return varInt(res); -} - -// Args: Str -scriptFunction(funcMmcMount){ - if (!TConf.keysDumped) - return ErrVar(ERRFATALFUNCFAIL); - - return varInt((mountMMCPart(vars[0].stringType).err)); -} - -// Args: Str -scriptFunction(funcMkdir){ - return varInt((f_mkdir(vars[0].stringType))); -} - -// Args: Str -scriptFunction(funcReadDir){ - int res = 0; - Vector_t files = ReadFolder(vars[0].stringType, &res); - if (res){ - clearFileVector(&files); - return ErrVar(ERRFATALFUNCFAIL); - } - - vecDefArray(FSEntry_t*, fsEntries, files); - - Vector_t fileNames = newVec(sizeof(char*), files.count); - Vector_t fileProperties = newVec(sizeof(int), files.count); - - for (int i = 0; i < files.count; i++){ - vecAddElem(&fileNames, fsEntries[i].name); - int isFolder = fsEntries[i].isDir; - vecAddElem(&fileProperties, isFolder); - } - - vecFree(files); - - dictVectorAdd(&ctx->varDict, newDict(CpyStr("fileProperties"), (newVar(IntArrayType, 1, .vectorType = fileProperties)))); - - return newVar(StringArrayType, 1, .vectorType = fileNames); -} - -// Args: Str, Str -scriptFunction(funcCopyDir){ - return varInt((FolderCopy(vars[0].stringType, vars[1].stringType).err)); -} - -// Args: Str -scriptFunction(funcDelDir){ - return varInt((FolderDelete(vars[0].stringType).err)); -} - -// Args: Str -scriptFunction(funcDelFile){ - return varInt((f_unlink(vars[0].stringType))); -} - -// Args: Str, Str -scriptFunction(funcMmcDump){ - return varInt((DumpOrWriteEmmcPart(vars[0].stringType, vars[1].stringType, 0, 1).err)); -} - -// Args: Str, Str, Int -scriptFunction(funcMmcRestore){ - return varInt((DumpOrWriteEmmcPart(vars[0].stringType, vars[1].stringType, 1, vars[2].integerType).err)); -} - -// Args: Str -scriptFunction(funcGetNcaType){ - if (!TConf.keysDumped) - return ErrVar(ERRFATALFUNCFAIL); - - return varInt((GetNcaType(vars[0].stringType))); -} - -// Args: Str -scriptFunction(funcSignSave){ - if (!TConf.keysDumped) - return ErrVar(ERRFATALFUNCFAIL); - - return varInt((saveCommit(vars[0].stringType).err)); -} - -scriptFunction(funcGetMs){ - return varInt(get_tmr_ms()); -} - -extern int launch_payload(char *path); - -// Args: Str -scriptFunction(funcLaunchPayload){ - return varInt(launch_payload(vars[0].stringType)); -} - -u8 fiveInts[] = {IntType, IntType, IntType, IntType, IntType}; -u8 singleIntArray[] = { IntArrayType }; -u8 singleInt[] = { IntType }; -u8 singleAny[] = { varArgs }; -u8 singleStr[] = { StringType }; -u8 singleByteArr[] = { ByteArrayType }; -u8 StrByteVec[] = { StringType, ByteArrayType}; -u8 MenuArgs[] = { StringArrayType, IntType, StringArrayType, IntArrayType}; -u8 twoStrings[] = { StringType, StringType }; -u8 mmcReadWrite[] = { StringType, StringType, IntType}; - -functionStruct_t scriptFunctions[] = { - {"if", funcIf, 1, singleInt}, - {"print", funcPrint, varArgs, NULL}, - {"println", funcPrintln, varArgs, NULL}, - {"while", funcWhile, 1, singleInt}, - {"else", funcElse, 0, NULL}, - {"len", funcLen, 1, singleAny}, - {"byte", funcMakeByteArray, 1, singleIntArray}, - {"setPixel", funcSetPixel, 5, fiveInts}, - {"fileRead", funcReadFile, 1, singleStr}, - {"fileWrite", funcWriteFile, 2, StrByteVec}, - {"fileExists", funcFileExists, 1, singleStr}, - {"bytesToStr", funcByteToStr, 1, singleByteArr}, - {"return", funcReturn, 0, NULL}, - {"exit", funcExit, 0, NULL}, - //{"continue", funcContinue, 0, NULL}, - {"printPos", funcSetPrintPos, 2, fiveInts}, - {"clearscreen", funcClearScreen, 0, NULL}, - {"drawBox", funcDrawBox, 5, fiveInts}, - {"color", funcSetColor, 1, singleStr}, - {"pause", funcPause, 0, NULL}, - {"wait", funcWait, 1, singleInt}, - {"version", funcGetVer, 0, NULL}, - {"menu", funcMakeMenu, 2, MenuArgs}, // for the optional arg - {"menu", funcMakeMenu, 3, MenuArgs}, - {"menu", funcMakeMenu, 4, MenuArgs}, - {"pathCombine", funcCombinePath, varArgs, NULL}, - {"pathEscFolder", funcEscFolder, 1, singleStr}, - {"fileMove", funcFileMove, 2, twoStrings}, - {"fileCopy", funcFileCopy, 2, twoStrings}, - {"fileDel", funcDelFile, 1, singleStr}, - {"mmcConnect", funcMmcConnect, 1, singleStr}, - {"mmcMount", funcMmcMount, 1, singleStr}, - {"mkdir", funcMkdir, 1, singleStr}, - {"dirRead", funcReadDir, 1, singleStr}, - {"dirCopy", funcCopyDir, 2, twoStrings}, - {"dirDel", funcDelDir, 1, singleStr}, - {"mmcDump", funcMmcDump, 2, mmcReadWrite}, - {"mmcRestore", funcMmcRestore, 3, mmcReadWrite}, - {"ncaGetType", funcGetNcaType, 1, singleStr}, - {"saveSign", funcSignSave, 1, singleStr}, - {"timerMs", funcGetMs, 0, NULL}, - {"launchPayload", funcLaunchPayload, 1, singleStr}, - // Left from old: keyboard(?) -}; - -Variable_t executeFunction(scriptCtx_t* ctx, char* func_name, lexarToken_t *start, u32 len) { - Vector_t args = { 0 }; - - if (len > 0) { - args = extractVars(ctx, start, len); - Variable_t* vars = vecGetArray(Variable_t*, args); - for (int i = 0; i < args.count; i++) { - if (vars[i].varType == ErrType) - return vars[i]; - } - } - - Variable_t* vars = vecGetArray(Variable_t*, args); - - for (u32 i = 0; i < ARRAY_SIZE(scriptFunctions); i++) { - if (scriptFunctions[i].argCount == args.count || scriptFunctions[i].argCount == varArgs) { - if (!strcmp(scriptFunctions[i].key, func_name)) { - if (scriptFunctions[i].argCount != varArgs && scriptFunctions[i].argCount != 0) { - u8 argsMatch = 1; - for (u32 j = 0; j < args.count; j++) { - if (vars[j].varType != scriptFunctions[i].typeArray[j] && scriptFunctions[i].typeArray[j] != varArgs) { - argsMatch = 0; - break; - } - } - - if (!argsMatch) - continue; - } - - Variable_t ret = scriptFunctions[i].value(ctx, vars, args.count); - freeVariableVector(&args); - return ret; - } - } - } - - Variable_t* var = dictVectorFind(&ctx->varDict, func_name); - if (var != NULL) { - if (var->varType == JumpType) { - setCurIndentInstruction(ctx, 0, 1, ctx->curPos); - ctx->curPos = var->integerType - 1; - return NullVar; - } - } - - return ErrVar(ERRNOFUNC); -} \ No newline at end of file diff --git a/source/script/functions.h b/source/script/functions.h deleted file mode 100644 index b5640e8..0000000 --- a/source/script/functions.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "variables.h" - -Variable_t executeFunction(scriptCtx_t* ctx, char* func_name, lexarToken_t* start, u32 len); \ No newline at end of file diff --git a/source/script/garbageCollector.c b/source/script/garbageCollector.c new file mode 100644 index 0000000..a0f51b1 --- /dev/null +++ b/source/script/garbageCollector.c @@ -0,0 +1,122 @@ +#include "model.h" +#include "genericClass.h" +#include "compat.h" +#include "garbageCollector.h" + +typedef struct { + Variable_t* ref; + u16 refCount; +} ReferenceCounter_t; + +Vector_t pendingAdd = { 0 }; +Vector_t pendingRemove = { 0 }; +Vector_t storedReferences = { 0 }; + +void initGarbageCollector() { + pendingAdd = newVec(sizeof(Variable_t*), 4); + pendingRemove = newVec(sizeof(Variable_t*), 4); + storedReferences = newVec(sizeof(ReferenceCounter_t), 8); +} + +// TODO: create binary tree for this! + +void modReference(Variable_t* ref, u8 add) { + if (ref == NULL || ref->gcDoNotFree) + return; + + ReferenceCounter_t* additionalFree = NULL; + + vecForEach(ReferenceCounter_t*, references, (&storedReferences)) { + if (!add && ( + (ref->variableType == FunctionClass && ref->function.builtIn && references->ref == ref->function.origin) || + (ref->variableType == SolvedArrayReferenceClass && references->ref == ref->solvedArray.arrayClassReference))) + if (--references->refCount <= 0) { + additionalFree = references; + continue; + } + + if (references->ref == ref) { + if (add) + references->refCount++; + else { + if (--references->refCount <= 0) { + freeVariable(&references->ref); + vecRem(&storedReferences, ((u8*)references - (u8*)storedReferences.data) / storedReferences.elemSz); + + if (additionalFree != NULL) { + freeVariable(&additionalFree->ref); + vecRem(&storedReferences, ((u8*)additionalFree - (u8*)storedReferences.data) / storedReferences.elemSz); + } + } + } + + return; + } + } + + if (!add) + return; + + ReferenceCounter_t r = { .ref = ref, .refCount = 1 }; + vecAdd(&storedReferences, r); +} +/* +void addPendingReference(Variable_t* ref) { + if (ref == NULL || ref->gcDoNotFree) + return; + + //vecAdd(&pendingAdd, ref); + + modReference(ref, 1); + + // TODO: freeing issues when trying a = 0 while(1) { a.print() 1.print() a = a + 1 } + + //if (pendingAdd.count >= 16) + // processPendingReferences(); +} + +void removePendingReference(Variable_t* ref) { + if (ref == NULL || ref->gcDoNotFree) + return; + + if (!ref->gcDoNotFree) { + if (ref->variableType == FunctionClass && ref->function.builtIn) { + removePendingReference(ref->function.origin); + } + + if (ref->variableType == SolvedArrayReferenceClass) { + removePendingReference(ref->solvedArray.arrayClassReference); + } + + modReference(ref, 0); + + //vecAdd(&pendingRemove, ref); + } +} +*/ + +void processPendingReferences() { + return; //stubbed + vecForEach(Variable_t**, references, (&pendingAdd)) + modReference(*references, 1); + + pendingAdd.count = 0; + + vecForEach(Variable_t**, references, (&pendingRemove)) + modReference(*references, 0); + + pendingRemove.count = 0; +} + +void exitGarbageCollector() { + processPendingReferences(); + + vecForEach(ReferenceCounter_t*, references, (&storedReferences)) { + gfx_printf("[WARN] referenced var %p at exit\n", references->ref); + freeVariable(&references->ref); + } + + vecFree(pendingAdd); + vecFree(pendingRemove); + vecFree(storedReferences); +} \ No newline at end of file diff --git a/source/script/garbageCollector.h b/source/script/garbageCollector.h new file mode 100644 index 0000000..e014ebe --- /dev/null +++ b/source/script/garbageCollector.h @@ -0,0 +1,12 @@ +#include "model.h" + +void initGarbageCollector(); +//void addPendingReference(Variable_t* ref); +void processPendingReferences(); +void exitGarbageCollector(); +//void removePendingReference(Variable_t* ref); + +void modReference(Variable_t* ref, u8 add); + +#define removePendingReference(ref) modReference(ref, 0) +#define addPendingReference(ref) modReference(ref, 1) \ No newline at end of file diff --git a/source/script/genericClass.c b/source/script/genericClass.c new file mode 100644 index 0000000..0f344e2 --- /dev/null +++ b/source/script/genericClass.c @@ -0,0 +1,264 @@ +#include "genericClass.h" +#include "model.h" +#include "intClass.h" +#include "compat.h" +#include "eval.h" +#include +#include "garbageCollector.h" +#include "StringClass.h" +#include "arrayClass.h" +#include "arrayReferenceClass.h" +#include "functionClass.h" +#include "scriptError.h" +#include "saveClass.h" +#include "unsolvedArrayClass.h" + +Variable_t* copyVariableToPtr(Variable_t var) { + Variable_t* a = malloc(sizeof(Variable_t)); + *a = var; + addPendingReference(a); + return a; +} + +MemberGetters_t memberGetters[] = { + {IntClass, getIntegerMember}, + {StringClass, getStringMember}, + {IntArrayClass, getArrayMember}, + {StringArrayClass, getArrayMember}, + {ByteArrayClass, getArrayMember}, + {SolvedArrayReferenceClass, getArrayReferenceMember}, + {UnresolvedArrayClass, getUnsolvedArrayMember}, +#ifndef WIN32 + {SaveClass, getSaveMember}, +#endif +}; + + +Variable_t* genericGet(Variable_t* var, CallArgs_t* ref) { + if (ref->extraAction == ActionExtraMemberName) { + for (u32 i = 0; i < ARRAY_SIZE(memberGetters); i++) { + if (var->variableType == memberGetters[i].classType) { + Variable_t member = memberGetters[i].func(var, ref->extra); + if (member.variableType == None) + return NULL; + + addPendingReference(var); // So caller doesn't fall out of scope. Don't forget to free! + return copyVariableToPtr(member); + } + } + + SCRIPT_FATAL_ERR("Did not find member '%s'", ref->extra); + } + else if (ref->extraAction == ActionExtraArrayIndex) { + Function_t* idx = ref->extra; + Variable_t *solvedIdx = eval(idx->operations.data, idx->operations.count, 1); + + if (solvedIdx->variableType != IntClass) { + SCRIPT_FATAL_ERR("Index is not an integer"); + return NULL; + } + + Variable_t* res = callMemberFunctionDirect(var, "get", &solvedIdx, 1); + removePendingReference(solvedIdx); + return res; + } + + return NULL; +} + +Variable_t* genericCallDirect(Variable_t* var, Variable_t** args, u8 len) { + if (var->variableType != FunctionClass) + return NULL; + + if (var->function.builtIn) { + for (u32 i = 0; i < var->function.len; i++) { + if (var->function.builtInPtr[i].argCount == len || var->function.builtInPtr[i].argCount == VARARGCOUNT) { + int valid = 1; + if (var->function.builtInPtr[i].argCount != VARARGCOUNT) { + for (u32 j = 0; j < var->function.builtInPtr[i].argCount; j++) { + if (var->function.builtInPtr[i].argTypes[j] != args[j]->variableType && var->function.builtInPtr[i].argTypes[j] != VARARGCOUNT) { + valid = 0; + break; + } + } + } + + if (valid) { + return var->function.builtInPtr[i].func(var->function.origin, args, len); + } + } + } + } + else { + Variable_t *ret = eval(var->function.function.operations.data, var->function.function.operations.count, 1); + if (ret == NULL) + return NULL; + removePendingReference(ret); + return &emptyClass; + } + + SCRIPT_FATAL_ERR("Arguments do not match function defenition(s)"); +} + +Variable_t* genericCall(Variable_t* var, CallArgs_t* ref) { + if (var->variableType != FunctionClass) + return NULL; + + if (var->function.builtIn) { + // TODO: implement arg handling + + Function_t* f = ref->extra; + if (f->operations.count == 0) { + return genericCallDirect(var, NULL, 0); + } + else { + //Vector_t argsHolder = newVec(sizeof(Variable_t*), 1); + Variable_t** argsHolder = NULL; + if (var->function.builtInPtr->argCount != 0) + argsHolder = malloc(sizeof(Variable_t*) * var->function.builtInPtr->argCount); + int argCount = 0; + int lasti = 0; + Operator_t* ops = f->operations.data; + + int tooManyArgs = 0; + + // Loops trough the function to get all args out + for (int i = 0; i < f->operations.count; i++) { + if (ops[i].token == EquationSeperator || i + 1 == f->operations.count) { + if (i + 1 == f->operations.count) + i++; + + if (argCount == var->function.builtInPtr->argCount) { + tooManyArgs = 1; + break; + } + + if (var->function.firstArgAsFunction && argCount == 0) { + Function_t f = { .operations = vecFromArray(&ops[lasti], i - lasti, sizeof(Operator_t)) }; + Variable_t var = newFunctionVariable(createFunctionClass(f, NULL)); + var.reference = 1; + Variable_t* varPtr = copyVariableToPtr(var); + //vecAdd(&argsHolder, varPtr); + argsHolder[argCount++] = varPtr; + } + else { + Variable_t* var = eval(&ops[lasti], i - lasti, 1); + if (var == NULL) + return NULL; // maybe free first? + + //vecAdd(&argsHolder, var); + argsHolder[argCount++] = var; + } + + lasti = i + 1; + } + } + + Variable_t* res = NULL; + + if (!tooManyArgs) + res = genericCallDirect(var, argsHolder, argCount); + else { + SCRIPT_FATAL_ERR("Too many args provided (got more than %d)", argCount); + } + + + for (int i = 0; i < argCount; i++) + removePendingReference(argsHolder[i]); + + //vecForEach(Variable_t**, tofree, (&argsHolder)) + // removePendingReference(*tofree); + + FREE(argsHolder); + + return res; + } + } + else { + Variable_t *ret = eval(var->function.function.operations.data, var->function.function.operations.count, 1); + if (ret == NULL) + return NULL; + removePendingReference(ret); + return &emptyClass; + } +} + +Variable_t getGenericFunctionMember(Variable_t* var, char* memberName, ClassFunctionTableEntry_t* entries, u8 len) { + Variable_t newVar = {.readOnly = 1, .variableType = FunctionClass}; + newVar.function.origin = var; + newVar.function.builtIn = 1; + for (u32 i = 0; i < len; i++) { + if (!strcmp(entries[i].name, memberName)) { + newVar.function.builtInPtr = &entries[i]; + + u32 j = i; + for (; j < len && !strcmp(entries[j].name, memberName); j++); + newVar.function.len = j - i; + + return newVar; + } + } + + return (Variable_t){ 0 }; +} + +Variable_t* callMemberFunction(Variable_t* var, char* memberName, CallArgs_t* args) { + for (u32 i = 0; i < ARRAY_SIZE(memberGetters); i++) { + if (var->variableType == memberGetters[i].classType) { + Variable_t funcRef = memberGetters[i].func(var, memberName); + if (funcRef.variableType == None) + return NULL; + + return genericCall(&funcRef, args); + } + } + + return NULL; +} + +Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable_t** args, u8 argsLen) { + for (u32 i = 0; i < ARRAY_SIZE(memberGetters); i++) { + if (var->variableType == memberGetters[i].classType) { + Variable_t funcRef = memberGetters[i].func(var, memberName); + if (funcRef.variableType == None) { + SCRIPT_FATAL_ERR("Did not find member '%s'", memberName); + } + + return genericCallDirect(&funcRef, args, argsLen); + } + } + + SCRIPT_FATAL_ERR("Could not find function table for given type"); + return NULL; +} + +void freeVariableInternal(Variable_t* referencedTarget) { + switch (referencedTarget->variableType) { + case StringClass: + if (referencedTarget->string.free) + gfx_printf("FREE STRING GETTING FREED AAA"); + FREE(referencedTarget->string.value); + break; + case StringArrayClass: + vecForEach(char**, stringsInArray, (&referencedTarget->solvedArray.vector)) { + FREE(*stringsInArray); + } + case ByteArrayClass: + case IntArrayClass: + vecFree(referencedTarget->solvedArray.vector); + break; + } +} + +void freeVariable(Variable_t** target) { + // Add specific freeing logic here + Variable_t* referencedTarget = *target; + + if (!referencedTarget->reference) { + freeVariableInternal(referencedTarget); + } + + + FREE(referencedTarget); + *target = NULL; +} \ No newline at end of file diff --git a/source/script/genericClass.h b/source/script/genericClass.h new file mode 100644 index 0000000..0f9fb4f --- /dev/null +++ b/source/script/genericClass.h @@ -0,0 +1,25 @@ +#pragma once +#include "model.h" + +Variable_t* copyVariableToPtr(Variable_t var); + +#define VARARGCOUNT 255 + +#define ClassFunction(name) Variable_t* name(Variable_t* caller, Variable_t** args, u8 argsLen) + + +typedef Variable_t (*getMemberFunction)(Variable_t*, char*); + +typedef struct { + u8 classType; + getMemberFunction func; +} MemberGetters_t; + +Variable_t getGenericFunctionMember(Variable_t* var, char* memberName, ClassFunctionTableEntry_t* entries, u8 len); +Variable_t* genericGet(Variable_t* var, CallArgs_t* ref); +Variable_t* genericCallDirect(Variable_t* var, Variable_t** args, u8 len); +Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable_t** args, u8 argsLen); +Variable_t* genericCall(Variable_t* var, CallArgs_t* ref); +void freeVariable(Variable_t** target); +Variable_t* callMemberFunction(Variable_t* var, char* memberName, CallArgs_t* args); +void freeVariableInternal(Variable_t* referencedTarget); \ No newline at end of file diff --git a/source/script/intClass.c b/source/script/intClass.c new file mode 100644 index 0000000..d03988e --- /dev/null +++ b/source/script/intClass.c @@ -0,0 +1,76 @@ +#include "intClass.h" +#include "compat.h" +#include +#include + +IntClass_t createIntClass(s64 in) { + IntClass_t a = { in }; + return a; +} + +Variable_t newIntVariable(s64 x) { + // Integers are always read-only + Variable_t var = { .variableType = IntClass, .readOnly = 1, .integer = createIntClass(x) }; + return var; +} + +ClassFunction(printIntVariable) { + IntClass_t* a = &caller->integer; + gfx_printf("%d", (int)a->value); + return &emptyClass; +} + +#define IntOpFunction(name, op) ClassFunction(name) { s64 i1 = getIntValue(caller); s64 i2 = getIntValue(*args); return newIntVariablePtr((i1 op i2)); } + +IntOpFunction(addInt, +) +IntOpFunction(minusInt, -) +IntOpFunction(multInt, *) +IntOpFunction(divInt, /) +IntOpFunction(modInt, %) +IntOpFunction(smallerInt, <) +IntOpFunction(biggerInt, >) +IntOpFunction(smallerEqInt, <=) +IntOpFunction(biggerEqInt, >=) +IntOpFunction(eqInt, ==) +IntOpFunction(notEqInt, !=) +IntOpFunction(logicAndInt, &&) +IntOpFunction(logicOrInt, ||) +IntOpFunction(andInt, &) +IntOpFunction(orInt, |) +IntOpFunction(bitshiftLeftInt, <<) +IntOpFunction(bitshiftRightInt, >>) + +ClassFunction(notInt) { + return newIntVariablePtr(!(getIntValue(caller))); +} + +u8 oneVarArgInt[] = { VARARGCOUNT }; +u8 oneIntArgInt[] = { IntClass }; + +#define IntOpFunctionEntry(opName, functionName) {opName, functionName, 1, oneIntArgInt} + +ClassFunctionTableEntry_t intFunctions[] = { + {"print", printIntVariable, 0, 0}, + {"not", notInt, 0, 0}, + IntOpFunctionEntry("+", addInt), + IntOpFunctionEntry("-", minusInt), + IntOpFunctionEntry("*", multInt), + IntOpFunctionEntry("/", divInt), + IntOpFunctionEntry("%", modInt), + IntOpFunctionEntry("<", smallerInt), + IntOpFunctionEntry(">", biggerInt), + IntOpFunctionEntry("<=", smallerEqInt), + IntOpFunctionEntry(">=", biggerEqInt), + IntOpFunctionEntry("==", eqInt), + IntOpFunctionEntry("!=", notEqInt), + IntOpFunctionEntry("&&", logicAndInt), + IntOpFunctionEntry("||", logicOrInt), + IntOpFunctionEntry("&", andInt), + IntOpFunctionEntry("|", orInt), + IntOpFunctionEntry("<<", bitshiftLeftInt), + IntOpFunctionEntry(">>", bitshiftRightInt), +}; + +Variable_t getIntegerMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, intFunctions, ARRAY_SIZE(intFunctions)); +} \ No newline at end of file diff --git a/source/script/intClass.h b/source/script/intClass.h new file mode 100644 index 0000000..c8138f1 --- /dev/null +++ b/source/script/intClass.h @@ -0,0 +1,13 @@ +#pragma once +#include "model.h" +#include "genericClass.h" + + + +#define getIntValue(var) (var)->integer.value + +IntClass_t createIntClass(s64 in); + +Variable_t newIntVariable(s64 x); +#define newIntVariablePtr(x) copyVariableToPtr(newIntVariable(x)) +Variable_t getIntegerMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/lexer.c b/source/script/lexer.c deleted file mode 100644 index 3bc203a..0000000 --- a/source/script/lexer.c +++ /dev/null @@ -1,308 +0,0 @@ -#include "lexer.h" -#include "types.h" -#include "args.h" -#include - -static inline int isValidWord(char c) { - char r = c | 0x20; - return ((r >= 'a' && r <= 'z') || c == '_'); -} - -static inline int isValidNum(char c) { - return (c >= '0' && c <= '9'); -} - -static inline int isValidVar(char c) { - return (isValidWord(c) || isValidNum(c)); -} - -static inline int isValidHexNum(char c) { - char r = c | 0x20; - return (isValidNum(r) || (r >= 'a' && r <= 'f')); -} - -#define makeLexarToken(token, var) ((lexarToken_t) {token, var}) - -typedef struct { - u8 tokenC; - u8 tokenN; -} lexarTranslation_t; - -lexarTranslation_t lexarTranslations[] = { - {'}', RCBracket}, - {',', Seperator}, - {'+', Plus}, - {'-', Minus}, - {'*', Multiply}, - {'/', Division}, - {'%', Mod}, - {'!', Not}, - {':', Selector}, - {')', RBracket}, - {']', RSBracket}, - {'(', LBracket}, - {'{', LCBracket}, - {'=', Equal}, - {'[', LSBracket}, - {'<', Smaller}, - {'>', Bigger}, - {'\0', 0}, -}; - -/* - Should we make vars with next char being '(' a function and vars with an equals (or [x] wait how are we gonna spot that) after it to be an assignmentVar -*/ - -char lexarDebugGetTokenC(u8 tokenN) { - for (int i = 0; lexarTranslations[i].tokenC; i++) { - if (lexarTranslations[i].tokenN == tokenN) { - return lexarTranslations[i].tokenC; - } - } - - if (tokenN == EquationSeperator) - return ';'; - - return '?'; -} - -/* -* !! we need to remake this -void lexarVectorClear(lexarVector_t* vec) { - for (int i = 0; i < vec->stored; i++) { - if (vec->tokens[i].token == Variable || vec->tokens[i].token == StrLit) - if (vec->tokens[i].text != NULL) - free(vec->tokens[i].text); - } - free(vec->tokens); -} -*/ - -void lexarVectorClear(Vector_t *v){ - vecPDefArray(lexarToken_t*, entries, v); - - for (int i = 0; i < v->count; i++){ - if (entries[i].token != IntLit && entries[i].text != NULL){ - free(entries[i].text); - } - } - - vecFreePtr(v); -} - -#define ELIFC(c) else if (*in == c) - -Vector_t runLexer(const char* in, u32 len) { - const char *start = in; - Vector_t vec = newVec(sizeof(lexarToken_t), 16); - // store last var for re-assignment - // var -> func if next obj is '(' - // var -> assignment if next obj is '=' - // var -> arrassignment if next obj is '[' and before '=' is ']' - // maybe measure len between ( ) and [ ], so this doesn't have to be done during runtime? - // We also have to support (()). maybe if '(' set indent level, then if ')' minus indent level, set len. indent level contains {u8 level, u16 token, u16 startoffset} - - u32 lastAssignment = 0; - - while ((in - start) < len) { - lexarToken_t* lx = vecGetArray(lexarToken_t*, vec); - - if ((lx[vec.count - 2].token == StrLit || lx[vec.count - 2].token == IntLit || lx[vec.count - 2].token == Variable || lx[vec.count - 2].token == RSBracket || lx[vec.count - 2].token == RBracket) - && (lx[vec.count - 1].token == Variable || lx[vec.count - 1].token == LCBracket || lx[vec.count - 1].token == RCBracket)) { - if (!(lx[lastAssignment].token == ArrayVariableAssignment && lx[vec.count - 1].token == Variable && lx[vec.count - 2].token == RSBracket)) { - lexarToken_t holder = lx[vec.count - 1]; - lx[vec.count - 1] = makeLexarToken(EquationSeperator, 0); - vecAddElement(&vec, holder); - lx = vecGetArray(lexarToken_t*, vec); - } - } - - if (isValidWord(*in)) { - char* startWord = in; - in++; - while (isValidVar(*in)) - in++; - - vecAddElement(&vec, (makeLexarToken(Variable, utils_copyStringSize(startWord, in - startWord)))); - continue; - } - else if (isValidNum(*in) || (*in == '-' && isValidNum(in[1]))) { - int parse = 0; - u8 negative = (*in == '-'); - if (negative) - in++; - - if (*in == '0' && (in[1] | 0x20) == 'x') { - in += 2; - while (isValidHexNum(*in)) { - parse = parse * 16 + (*in & 0x0F) + (*in >= 'A' ? 9 : 0); - in++; - } - } - else while (isValidNum(*in)) { - parse = parse * 10 + *in++ - '0'; - } - - if (negative) - parse *= -1; - - vecAddElement(&vec, makeLexarToken(IntLit, parse)); - continue; - } - ELIFC('(') { - if (lx[vec.count - 1].token == Variable) - lx[vec.count - 1].token = Function; - - vecAddElement(&vec, makeLexarToken(LBracket, 0)); - } - ELIFC('[') { - if (lx[vec.count - 1].token == Variable) - lx[vec.count - 1].token = ArrayVariable; - - vecAddElement(&vec, makeLexarToken(LSBracket, 0)); - } - ELIFC('=') { // Do we need to keep = if the vars are assignments anyway? - if (in[1] == '='){ - vecAddElement(&vec, makeLexarToken(EqualEqual, 0)); - in++; - continue; - } - - if (lx[vec.count - 1].token == Variable) - lx[vec.count - 1].token = VariableAssignment; - - else if (lx[vec.count - 1].token == RSBracket) { - int back = 1; - while (lx[vec.count - back].token != ArrayVariable) { - back++; - if (vec.count - back < 0) - break; // major error - } - if (lx[vec.count - back].token == ArrayVariable) { - lx[vec.count - back].token = ArrayVariableAssignment; - lastAssignment = vec.count - back; - in++; - continue; - } - } - lastAssignment = 0; - } - ELIFC('{') { - if (lx[vec.count - 1].token == VariableAssignment) { - lx[vec.count - 1].token = FunctionAssignment; - } - vecAddElement(&vec, makeLexarToken(LCBracket, 0)); - } - ELIFC('"') { - char* startStr = ++in; - int len = 0; - while (*in != '"') { - in++; - } - len = in - startStr; - - char* storage = malloc(len + 1); - - int pos = 0; - for (int i = 0; i < len; i++) { - if (startStr[i] == '\\') { - if (startStr[i + 1] == 'n') { - storage[pos++] = '\n'; - i++; - continue; - } - - if (startStr[i + 1] == 'r') { - storage[pos++] = '\r'; - i++; - continue; - } - } - storage[pos++] = startStr[i]; - } - storage[pos] = '\0'; - - vecAddElement(&vec, makeLexarToken(StrLit, storage)); - } - ELIFC('#') { - while (*in != '\n') - in++; - } - ELIFC('&') { - if (in[1] == '&') { - vecAddElement(&vec, makeLexarToken(LogicAND, 0)); - in++; - } - else { - vecAddElement(&vec, makeLexarToken(AND, 0)); - } - } - ELIFC('|') { - if (in[1] == '|') { - vecAddElement(&vec, makeLexarToken(LogicOR, 0)); - in++; - } - else { - vecAddElement(&vec, makeLexarToken(OR, 0)); - } - } - ELIFC('>'){ - if (in[1] == '>'){ - vecAddElement(&vec, makeLexarToken(BitShiftRight, 0)); - in++; - } - else { - int a = (in[1] == '=') ? 1 : 0; - vecAddElement(&vec, makeLexarToken(Bigger, 0)); - in += a; - } - - } - ELIFC('<'){ - if (in[1] == '<'){ - vecAddElement(&vec, makeLexarToken(BitShiftLeft, 0)); - in++; - } - else { - int a = (in[1] == '=') ? 1 : 0; - vecAddElement(&vec, makeLexarToken(Smaller + a, 0)); - in += a; - } - - } - else { - int val = 0; - - for (int i = 0; lexarTranslations[i].tokenC; i++) { - if (lexarTranslations[i].tokenC == *in) { - val = lexarTranslations[i].tokenN; - break; - } - } - - in++; - - if (*in == '=' && val >= Smaller && val <= Not) { - val++; - in++; - } - - if (val != Invalid) - vecAddElement(&vec, makeLexarToken(val, 0)); - - continue; - } - in++; - } - - lexarToken_t* lx = vecGetArray(lexarToken_t*, vec); - if ((lx[vec.count - 2].token == StrLit || lx[vec.count - 2].token == IntLit || lx[vec.count - 2].token == Variable || lx[vec.count - 2].token == RSBracket || lx[vec.count - 2].token == RBracket) - && (lx[vec.count - 1].token == Variable || lx[vec.count - 1].token == LCBracket || lx[vec.count - 1].token == RCBracket)) { - lexarToken_t holder = lx[vec.count - 1]; - lx[vec.count - 1] = makeLexarToken(EquationSeperator, 0); - vecAddElement(&vec, holder); - } - - vecAddElement(&vec, makeLexarToken(EquationSeperator, 0)); - return vec; -} \ No newline at end of file diff --git a/source/script/lexer.h b/source/script/lexer.h deleted file mode 100644 index a6b5d42..0000000 --- a/source/script/lexer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "types.h" - -Vector_t runLexer(const char* in, u32 len); -char lexarDebugGetTokenC(u8 tokenN); -void lexarVectorClear(Vector_t *v); \ No newline at end of file diff --git a/source/script/model.c b/source/script/model.c new file mode 100644 index 0000000..bb39fb8 --- /dev/null +++ b/source/script/model.c @@ -0,0 +1,43 @@ +#include "model.h" +#include "compat.h" +#include "StringClass.h" +#include "intClass.h" + +TokenConvertion_t tokenConvertions[] = { + {SmallerEqual, "<="}, + {BiggerEqual, ">="}, + {NotEqual, "!="}, + {LogicAnd, "&&"}, + {LogicOr, "||"}, + {EqualEqual, "=="}, + + {BitShiftLeft, "<<"}, + {BitShiftRight, ">>"}, + + {Not, "!"}, + {Plus, "+"}, + {Equals, "="}, + {Minus, "-"}, + {Multiply, "*"}, + {Division, "/"}, + {Modulo, "%"}, + + {LeftSquareBracket, "["}, + {LeftCurlyBracket, "{"}, + {LeftBracket, "("}, + {RightSquareBracket, "]"}, + {RightCurlyBracket, "}"}, + {RightBracket, ")"}, + + {Smaller, "<"}, + {Bigger, ">"}, + + {And, "&"}, + {Or, "|"}, + {Dot, "."}, + {EquationSeperator, ","}, +}; + +u32 tokenConvertionCount = ARRAY_SIZE(tokenConvertions); + +Variable_t emptyClass = { .variableType = EmptyClass, .readOnly = 1, .reference = 1, .gcDoNotFree = 1 }; \ No newline at end of file diff --git a/source/script/model.h b/source/script/model.h new file mode 100644 index 0000000..c6fe409 --- /dev/null +++ b/source/script/model.h @@ -0,0 +1,269 @@ +#pragma once + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef long long s64; + + + +#ifdef WIN32 +#pragma pack(1) +typedef struct { + void* data; + u32 capacity; + u32 count; + u8 elemSz; +} Vector_t; +#else +#include "../utils/vector.h" +#include +#pragma pack(1) +#endif + + +typedef enum { + None = 0, + IntClass, + FunctionClass, + StringClass, + ByteArrayClass, + StringArrayClass, + IntArrayClass, + UnresolvedArrayClass, + DictionaryClass, + EmptyClass, + SolvedArrayReferenceClass, + SaveClass, +} VariableType_t; + +typedef enum { + Invalid = 0, + Variable, + BetweenBrackets, + Not, + + Plus, + Equals, + Minus, + Multiply, + Division, + Modulo, + + LeftSquareBracket, + LeftCurlyBracket, + LeftBracket, + RightSquareBracket, + RightCurlyBracket, + RightBracket, + + Smaller, + SmallerEqual, + Bigger, + BiggerEqual, + EqualEqual, + NotEqual, + LogicAnd, + LogicOr, + + BitShiftLeft, + BitShiftRight, + And, + Or, + + EquationSeperator, + Dot, + CallArgs, +} Token_t; + +typedef enum { + ActionGet = 0, + ActionSet, + ActionCall, +} ActionType_t; + +typedef enum { + ActionExtraNone = 0, + ActionExtraArrayIndex, + ActionExtraMemberName, + ActionExtraCallArgs, + ActionExtraCallArgsFunction +} ActionExtraType_t; + + +// Change to a Vector_t with Operator_t's +typedef struct { + Vector_t operations; // Operation_t. Equations seperated by EquationSep +} Function_t; + +struct _ClassFunctionTableEntry_t; +struct _Variable_t; + +typedef struct _FunctionClass_t { + union { + struct { + u8 builtIn : 1; + u8 firstArgAsFunction : 1; + }; + u8 unionFunctionOptions; + }; + union { + Function_t function; + struct { + struct _ClassFunctionTableEntry_t* builtInPtr; + struct _Variable_t* origin; + u8 len; + }; + + }; + +} FunctionClass_t; + +typedef enum { + ArrayType_Int = 0, + ArrayType_String, + ArrayType_Byte +} ArrayType_t; + +typedef struct { + union { + Vector_t vector; // vector of typeof(value) + struct { + struct _Variable_t* arrayClassReference; + u32 offset; + u32 len; + }; + }; + +} ArrayClass_t; + +typedef struct _UnsolvedArrayClass_t { + Vector_t operations; // Operator_t +} UnsolvedArrayClass_t; + +typedef struct _DictionaryClass_t { + Vector_t vector; // vector of typeof(Dict_t) +} DictionaryClass_t; + +typedef struct _IntClass_t { + s64 value; +} IntClass_t; + +typedef struct _StringClass_t { + char* value; + struct { + u8 free : 1; + }; +} StringClass_t; + +#ifndef WIN32 +typedef struct { + save_ctx_t saveCtx; + FIL saveFile; +} SaveClass_t; +#endif + +typedef struct _Variable_t { + //void* variable; + union { + FunctionClass_t function; + UnsolvedArrayClass_t unsolvedArray; + DictionaryClass_t dictionary; + IntClass_t integer; + StringClass_t string; + ArrayClass_t solvedArray; + #ifndef WIN32 + SaveClass_t *save; + #endif + }; + union { + struct { + u8 variableType : 5; + u8 readOnly : 1; + u8 reference : 1; + u8 gcDoNotFree : 1; + }; + }; +} Variable_t; + +typedef struct _CallArgs_t { + struct { + u8 action : 4; + u8 extraAction : 4; + }; + void* extra; // Function_t for arrayIdx, char* for member, Function_t for funcCall, Function_t x2 for funcCallArgs + struct _CallArgs_t* next; +} CallArgs_t; + +typedef struct { + void* data; + u32 len; +} Array_t; + +typedef Variable_t* (*ClassFunction)(Variable_t* caller, Variable_t** args, u8 argsLen); + +typedef struct _ClassFunctionTableEntry_t { + char* name; + ClassFunction func; + u8 argCount; + u8* argTypes; +} ClassFunctionTableEntry_t; + +typedef struct _VariableReference_t { + union { + struct { + u8 staticVariableSet : 1; + u8 staticVariableRef : 1; + u8 staticVariableType : 2; // 0 = ref, 1 = int, 2 = str, 3 = stdlib func + }; + u8 staticVariableOptionsUnion; + }; + + union { + Variable_t* staticVariable; + char* name; + Array_t betweenBrackets; + s64 integerType; + char* stringType; + ClassFunctionTableEntry_t* staticFunction; + }; +} VariableReference_t; + +//typedef Variable_t* (*classFunctionTable)(VariableReference_t*); + +typedef Variable_t* (*classFunctionTable)(char*, Variable_t*, VariableReference_t*, Vector_t*); + +typedef struct { + char* name; + Variable_t* var; +} Dict_t; + +typedef struct { + u8 token : 8; + char strToken[3]; +} TokenConvertion_t; + +extern TokenConvertion_t tokenConvertions[]; +extern u32 tokenConvertionCount; + +typedef struct { + Vector_t operations; // Operator_t +} Equation_t; + +typedef struct { + struct { + u8 token : 7; + u8 not : 1; + }; + union { + VariableReference_t variable; + CallArgs_t callArgs; + char* tokenStr; + s64 lineNumber; + }; + // probably should add u16 lineNum here +} Operator_t; + +extern Variable_t emptyClass; + +#pragma pack() \ No newline at end of file diff --git a/source/script/parser.c b/source/script/parser.c index 21104f0..fe24daf 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -1,130 +1,636 @@ -#include "args.h" -#include "types.h" -#include "variables.h" -#include "lexer.h" -#include "../gfx/gfx.h" -#include "../utils/utils.h" -#include -#include "../hid/hid.h" +#include "model.h" +#include "compat.h" +#include "compat.h" +#include "parser.h" +#include +#include -#define scriptResultCreate(resCode, nearToken) (scriptResult_t) {resCode, nearToken, 1} -#define scriptResultCreateLen(resCode, nearToken, len) (scriptResult_t) {resCode, nearToken, len} +#include "intClass.h" +#include "StringClass.h" +#include "unsolvedArrayClass.h" +#include "functionClass.h" -scriptResult_t runFunction(scriptCtx_t* ctx, u32 len) { - lexarToken_t* tokens = vecGetArray(lexarToken_t*, ctx->script); - Variable_t res = solveEquation(ctx, &tokens[ctx->startEquation], len, 1); +#include "scriptError.h" +#include "standardLibrary.h" - if (res.varType == ErrType) { - return scriptResultCreateLen(res.integerType, &tokens[ctx->startEquation], len); +static inline int isValidWord(char c) { + char r = c | 0x20; + return ((r >= 'a' && r <= 'z') || c == '_'); +} + +static inline int isValidNum(char c) { + return (c >= '0' && c <= '9'); +} + +static inline int isValidVar(char c) { + return (isValidWord(c) || isValidNum(c)); +} + +static inline int isValidHexNum(char c) { + char r = c | 0x20; + return (isValidNum(r) || (r >= 'a' && r <= 'f')); +} + +char* getTokenText(u8 token) { + for (u32 i = 0; i < tokenConvertionCount; i++) { + if (tokenConvertions[i].token == token) + return tokenConvertions[i].strToken; } - return scriptResultCreate(0, 0); + return NULL; } -#define RUNFUNCWITHPANIC(ctx, len) scriptResult_t res = runFunction(ctx, len); if (res.resCode != 0) return res +char* utils_copyStringSize(const char* in, int size) { + if (size > strlen(in) || size < 0) + size = strlen(in); -static inline int checkIfVar(u8 token) { - return (token == StrLit || token == IntLit || token == Variable || token == RSBracket || token == ArrayVariable); + char* out = calloc(size + 1, 1); + //strncpy(out, in, size); + if (size) + memcpy(out, in, size); + return out; } -scriptResult_t mainLoop(scriptCtx_t* ctx) { - ctx->startEquation = 0; - lexarToken_t* lexArr = vecGetArray(lexarToken_t*, ctx->script); - for (ctx->curPos = 0; ctx->curPos < ctx->script.count; ctx->curPos++) { - u32 i = ctx->curPos; - lexarToken_t curToken = lexArr[i]; +#define ELIFC(c) else if (*in == c) - if (curToken.token == EquationSeperator) { - RUNFUNCWITHPANIC(ctx, ctx->curPos - ctx->startEquation); - ctx->startEquation = ctx->curPos + 1; - } - else if (curToken.token == FunctionAssignment) { - setCurIndentInstruction(ctx, 1, 0, -1); - dict_t x = newDict(CpyStr(curToken.text), newVar(JumpType, 0, .integerType = ctx->curPos + 1)); - vecAddElement(&ctx->varDict, x); - } - else if (curToken.token == LCBracket) { - indentInstructor_t* ins = getCurIndentInstruction(ctx); - if (ins->active) { - if (ins->skip) { - int distance = distanceBetweenTokens(&lexArr[i + 1], ctx->script.count - i - 1, LCBracket, RCBracket); - if (distance < 0) - return scriptResultCreate(ERRSYNTAX, &lexArr[i]); - ctx->curPos += distance + 1; - } - else - ctx->indentIndex++; - } - else - return scriptResultCreate(ERRINACTIVEINDENT, &lexArr[i]); +Vector_t script; +s64 lineNumber; - ctx->startEquation = ctx->curPos + 1; - } - else if (curToken.token == RCBracket) { - ctx->indentIndex--; - indentInstructor_t* ins = getCurIndentInstruction(ctx); - if (ins->active && ins->jump) { - ctx->curPos = ins->jumpLoc - 1; - } - - ins->active = 0; - ctx->startEquation = ctx->curPos + 1; - } - } - - return scriptResultCreate(0, 0); -} - -void printToken(lexarToken_t* token) { - switch (token->token) { - case Variable: - case ArrayVariable: - case Function: - gfx_printf("%s", token->text); - break; - case FunctionAssignment: - case VariableAssignment: - case ArrayVariableAssignment: - gfx_printf("%s=", token->text); - break; - case StrLit: - //printf("%d: '%s'\n", vec.tokens[i].token, vec.tokens[i].text); - gfx_printf("\"%s\"", token->text); - break; - case IntLit: - //printf("%d: %d\n", vec.tokens[i].token, vec.tokens[i].val); - gfx_printf("%d", token->val); - break; - default: - //printf("%d: %c\n", vec.tokens[i].token, lexarDebugGetTokenC(vec.tokens[i].token)); - gfx_printf("%c", lexarDebugGetTokenC(token->token)); - break; - } -} - -char *ErrorText[] = { - "Bad operator", - "Double not", - "Syntax err", - "Invalid type", - "No var", - "No func", - "Inactive indent", - "Div by 0", - "Func fail" +enum TokenType { + Token_Variable = 0, + Token_String, + Token_Int, + Token_Token, + Token_Err, + Token_Fatal_Err, }; -void printError(scriptResult_t res) { - if (res.resCode) { - if (res.resCode == ERRESCSCRIPT) - return; +typedef enum { + History_Function = 0, + History_Bracket, + History_Array, +} StackHistory_t; - gfx_printf("Error found! %s\nNear: ", ErrorText[res.resCode - 1]); - for (int i = 0; i < res.len; i++) { - printToken(&res.nearToken[i]); +u8 nextToken(char** inPtr, void** val) { + char* in = *inPtr; + u8 ret = Token_Err; + while (ret == Token_Err) { + if (*in == '#') { + if (!memcmp(in + 1, "REQUIRE ", 8)) { + if (!memcmp(in + 9, "VER ", 4)) { + u8 vers[3] = { 0 }; + char* verStart = in + 13; + for (u8 i = 0; i < 3; i++) { + while (isValidNum(*verStart)) { + vers[i] = vers[i] * 10 + *verStart++ - '0'; + } + verStart++; + } + + u8 outdated = 0; + if (vers[0] > LP_VER_MJ) + outdated = 1; + else if (vers[0] == LP_VER_MJ) { + if (vers[1] > LP_VER_MN) + outdated = 1; + else if (vers[1] == LP_VER_MN) { + if (vers[2] > LP_VER_BF) + outdated = 1; + } + } + + if (outdated) { + printScriptError(SCRIPT_FATAL, "Script requires TegraExplorer %d.%d.%d or up!", vers[0], vers[1], vers[2]); + return Token_Fatal_Err; + } + } + else if (!memcmp(in + 9, "MINERVA", 7)) { + u8 minervaEnabled = 0; // TODO: Change this to the actual value + if (!minervaEnabled) { + printScriptError(SCRIPT_FATAL, "Extended memory required.\nPut the bootloader folder from hekate on your sd!"); + return Token_Fatal_Err; + } + } + } + + while (*in && *in != '\n') + in++; + } + else if (isValidWord(*in)) { + char* startWord = in; + in++; + while (isValidVar(*in)) + in++; + + char* str = utils_copyStringSize(startWord, in - startWord); + + //gfx_printf("Variable: '%s'\n", str); + ret = Token_Variable; + *val = str; + break; + } + else if (isValidNum(*in) || (*in == '-' && isValidNum(in[1]))) { + s64 parse = 0; + u8 negative = (*in == '-'); + if (negative) + in++; + + if (*in == '0' && (in[1] | 0x20) == 'x') { + in += 2; + while (isValidHexNum(*in)) { + parse = parse * 16 + (*in & 0x0F) + (*in >= 'A' ? 9 : 0); + in++; + } + } + else while (isValidNum(*in)) { + parse = parse * 10 + *in++ - '0'; + } + + if (negative) + parse *= -1; + + //gfx_printf("Integer: '%d'\n", parse); + ret = Token_Int; + + s64* parsePersistent = malloc(sizeof(s64)); + *parsePersistent = parse; + + *val = parsePersistent; + break; + } + ELIFC('"') { + char* startStr = ++in; + int len = 0; + while (*in != '"') { + in++; + } + len = in - startStr; + + char* storage = malloc(len + 1); + + int pos = 0; + for (int i = 0; i < len; i++) { + if (startStr[i] == '\\') { + if (startStr[i + 1] == 'n') { + storage[pos++] = '\n'; + i++; + continue; + } + + if (startStr[i + 1] == 'r') { + storage[pos++] = '\r'; + i++; + continue; + } + } + storage[pos++] = startStr[i]; + } + storage[pos] = '\0'; + + //gfx_printf("String: '%s'\n", storage); + ret = Token_String; + *val = storage; + } + else if (*in == '\0') { + *inPtr = in; + return ret; + } + else if (*in == '\n'){ + lineNumber++; + scriptCurrentLine = lineNumber; + } + else { + for (u32 i = 0; i < tokenConvertionCount; i++) { + TokenConvertion_t t = tokenConvertions[i]; + if (!memcmp(t.strToken, in, (t.strToken[1] == '\0') ? 1 : 2)) { + //gfx_printf("Token: '%s'\n", t.strToken); + ret = Token_Token; + *val = t.token; + + if (t.strToken[1] != '\0') + in++; + + break; + } + } + } + in++; + } + + *inPtr = in; + return ret; +} + +#define CreateVariableReferenceStatic(var) VariableReference_t reference = { .staticVariable = var, .staticVariableSet = 1, .staticVariableRef = 1 } +#define CreateVariableReferenceStr(str) VariableReference_t reference = { .name = str } + +void setNextActionOperator(Vector_t *opHolder, ActionType_t action, ActionExtraType_t actionExtra, void *extra) { + Operator_t* ops = opHolder->data; + Operator_t* lastOp = &ops[opHolder->count - 1]; + + if (lastOp->token == CallArgs) { + CallArgs_t* last = &lastOp->callArgs; + for (; last->next != NULL; last = last->next); + last->next = calloc(sizeof(CallArgs_t), 1); + last->next->action = action; + last->next->extra = extra; + last->next->extraAction = actionExtra; + } + else { + Operator_t newOp = { .token = CallArgs }; + newOp.callArgs.action = action; + newOp.callArgs.extra = extra; + newOp.callArgs.extraAction = actionExtra; + vecAdd(opHolder, newOp); + } +} + +CallArgs_t* getLastRef(CallArgs_t* ref) { + for (; ref->next != NULL; ref = ref->next); + return ref; +} + +int isLastVarSet(Operator_t* opHolder) { + return (opHolder->token == CallArgs && getLastRef(&opHolder->callArgs)->action == ActionSet); +} + +int isLastVarCall(Operator_t* opHolder) { + return (opHolder->token == CallArgs && getLastRef(&opHolder->callArgs)->action == ActionCall); +} + +ParserRet_t parseScript(char* in) { + Vector_t functionStack; // Function_t + Vector_t stackHistoryHolder; // StaticHistory_t + Vector_t staticVariableHolder; // Variable_t + + functionStack = newVec(sizeof(Function_t), 0); + Function_t firstFunction = createEmptyFunction(); + vecAdd(&functionStack, firstFunction); + + staticVariableHolder = newVec(sizeof(Variable_t), 0); + + stackHistoryHolder = newVec(sizeof(StackHistory_t), 1); + StackHistory_t firstHistory = History_Function; + vecAdd(&stackHistoryHolder, firstHistory); + u8 notNext = 0; + lineNumber = 1; + scriptCurrentLine = 1; + + while (*in) { + Function_t* lastFunc = getStackEntry(&functionStack); + StackHistory_t* lastHistory = getStackEntry(&stackHistoryHolder); + + Operator_t* lastOp = NULL; + + if (lastFunc) { + lastOp = getStackEntry(&lastFunc->operations); } - gfx_printf("\nPress any key to exit"); - hidWait(); + void* var = NULL; + u8 tokenType = nextToken(&in, &var); + + if (tokenType == Token_Err) + break; + + if (tokenType == Token_Fatal_Err) + return (ParserRet_t) { 0 }; + + Operator_t op = { .token = Variable }; + + if (tokenType >= Token_Variable && tokenType <= Token_Int && lastOp) { + if (lastOp->token == Variable || lastOp->token == BetweenBrackets || (lastOp->token == CallArgs && !isLastVarSet(lastOp))) { + op.token = EquationSeperator; + op.lineNumber = lineNumber; + vecAdd(&lastFunc->operations, op); + op.token = Variable; + } + } + + if (tokenType == Token_Variable) { + + ClassFunctionTableEntry_t* cfte = searchStdLib(var); + + if (cfte == NULL) { + CreateVariableReferenceStr(var); + op.variable = reference; + } + else { + VariableReference_t reference = { .staticVariableType = 3, .staticFunction = cfte }; + op.variable = reference; + } + } + else if (tokenType == Token_Int) { + /* + Variable_t a = newIntVariable(*((s64*)var)); + a.gcDoNotFree = 1; + free(var); + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + */ + + VariableReference_t reference = { .staticVariableType = 1, .integerType = *((s64*)var) }; + op.variable = reference; + free(var); + } + else if (tokenType == Token_String) { + /* + Variable_t a = newStringVariable(var, 1, 1); + a.gcDoNotFree = 1; + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + */ + + VariableReference_t reference = { .staticVariableType = 2, .stringType = var }; + op.variable = reference; + } + else if (tokenType == Token_Token) { + u8 token = (u8)var; + + if (token == Equals && lastOp) { + if (lastOp->token == Variable) { + if (lastOp->variable.staticVariableSet) { + SCRIPT_PARSER_ERR("Trying to assign to a static variable"); + } + else { + setNextActionOperator(&lastFunc->operations, ActionSet, ActionExtraNone, NULL); + continue; + } + } + else if (lastOp->token == CallArgs) { + CallArgs_t* last = getLastRef(&lastOp->callArgs); + last->action = ActionSet; + continue; + } + else { + SCRIPT_PARSER_ERR("Trying to assign to non-object"); + } + } + else if (token == LeftCurlyBracket) { + Function_t templateFunction = createEmptyFunction(); + vecAdd(&functionStack, templateFunction); + + StackHistory_t functionHistory = History_Function; + vecAdd(&stackHistoryHolder, functionHistory); + continue; + } + else if (token == RightCurlyBracket) { + if (stackHistoryHolder.count != 1 && *lastHistory == History_Function) { + Function_t *popFunc = popStackEntry(&functionStack); + popStackEntry(&stackHistoryHolder); + + lastFunc = getStackEntry(&functionStack); + + if (lastFunc) { // TODO: Add check for null deref + lastOp = getStackEntry(&lastFunc->operations); + } + + if (lastOp && (lastOp->token == Variable || (lastOp->token == CallArgs && !isLastVarSet(lastOp)))) { + if (lastOp->token == Variable) { + SCRIPT_PARSER_ERR("GET variable before {}"); + continue; + } + + CallArgs_t* lastCall = getLastRef(&lastOp->callArgs); + if (lastCall->extraAction == ActionExtraCallArgs) { + Function_t* funcArgs = lastCall->extra; + + op.token = EquationSeperator; + op.lineNumber = lineNumber; + vecAdd(&funcArgs->operations, op); + op.token = Variable; + + Variable_t a = newFunctionVariable(createFunctionClass(*popFunc, NULL)); + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + op.variable = reference; + vecAdd(&funcArgs->operations, op); + continue; + } + } + + + + Variable_t a = newFunctionVariable(createFunctionClass(*popFunc, NULL)); + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + op.variable = reference; + vecAdd(&lastFunc->operations, op); + + op.token = EquationSeperator; + op.lineNumber = lineNumber; + vecAdd(&lastFunc->operations, op); + } + else { + SCRIPT_PARSER_ERR("Stack count is 1 or state is not a function"); + } + } + else if (token == Dot) { + if (lastOp && (lastOp->token == Variable || lastOp->token == BetweenBrackets || (lastOp->token == CallArgs && !isLastVarSet(lastOp)))) { + tokenType = nextToken(&in, &var); + if (tokenType != Token_Variable) { + SCRIPT_PARSER_ERR("Acessing member with non-dynamic token"); + } + else { + setNextActionOperator(&lastFunc->operations, ActionGet, ActionExtraMemberName, var); + continue; + } + } + else { + SCRIPT_PARSER_ERR("Member access on non-variable"); + } + } + else if (token == LeftBracket) { + Function_t templateFunction = createEmptyFunction(); + vecAdd(&functionStack, templateFunction); + + StackHistory_t functionHistory = History_Bracket; + vecAdd(&stackHistoryHolder, functionHistory); + continue; + } + else if (token == RightBracket) { + if (*lastHistory == History_Bracket) { + Function_t* bstack = popStackEntry(&functionStack); + popStackEntry(&stackHistoryHolder); + lastFunc = getStackEntry(&functionStack); + + if (lastFunc) { // TODO: Add check for null deref + lastOp = getStackEntry(&lastFunc->operations); + } + + if (lastOp && (lastOp->token == Variable || lastOp->token == BetweenBrackets || (lastOp->token == CallArgs && !isLastVarSet(lastOp) && !isLastVarCall(lastOp)))) { + Function_t* newBStack = malloc(sizeof(Function_t)); + *newBStack = *bstack; + setNextActionOperator(&lastFunc->operations, ActionCall, ActionExtraCallArgs, newBStack); // Maybe pass NULL if array is empty? + continue; + } + else { + if (lastOp && isLastVarCall(lastOp)) { + op.token = EquationSeperator; + vecAdd(&lastFunc->operations, op); + } + + if (!countTokens(bstack, EquationSeperator)) { + op.variable.betweenBrackets.data = bstack->operations.data; + op.variable.betweenBrackets.len = bstack->operations.count; + op.token = BetweenBrackets; + } + else { + SCRIPT_PARSER_ERR("Priority brackets can only contain 1 argument"); + } + + } + } + else { + SCRIPT_PARSER_ERR(") without ("); + } + } + else if (token == LeftSquareBracket) { + Function_t templateFunction = createEmptyFunction(); + vecAdd(&functionStack, templateFunction); + + StackHistory_t functionHistory = History_Array; + vecAdd(&stackHistoryHolder, functionHistory); + continue; + } + else if (token == RightSquareBracket) { + if (*lastHistory == History_Array) { + Function_t* astack = popStackEntry(&functionStack); + popStackEntry(&stackHistoryHolder); + lastFunc = getStackEntry(&functionStack); + + if (lastFunc) { // TODO: Add check for null deref + lastOp = getStackEntry(&lastFunc->operations); + } + + if (lastOp && (lastOp->token == Variable || (lastOp->token == CallArgs && !isLastVarSet(lastOp)))) { + if (!countTokens(astack, EquationSeperator)) { + Function_t* newAStack = malloc(sizeof(Function_t)); + *newAStack = *astack; + setNextActionOperator(&lastFunc->operations, ActionGet, ActionExtraArrayIndex, newAStack); + continue; + } + else { + // We're just assuming that it's a new array lol + + op.token = EquationSeperator; + vecAdd(&lastFunc->operations, op); + op.token = Variable; + + + Variable_t a = createUnsolvedArrayVariable(astack); + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + op.variable = reference; + + //gfx_printf("[FATAL] indexes cannot contain mutiple arguments"); + } + } + else { + // TODO: optimize output to a typed array, if possible + Variable_t a = createUnsolvedArrayVariable(astack); + vecAdd(&staticVariableHolder, a); + CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); + op.variable = reference; + } + } + else { + SCRIPT_PARSER_ERR("] without ["); + } + } + else if (token == Not) { + notNext = !notNext; + continue; + } + else { + op.token = token; + + for (u32 i = 0; i < tokenConvertionCount; i++) { + if (token == tokenConvertions[i].token) { + op.tokenStr = tokenConvertions[i].strToken; + break; + } + } + } + } + + if (notNext) { + op.not = 1; + notNext = 0; + } + + vecAdd(&lastFunc->operations, op); + } + + if (functionStack.count != 1 || stackHistoryHolder.count != 1) { + SCRIPT_PARSER_ERR("There seems to be an open bracket somewhere. EOF reached"); + } + + + ParserRet_t parse = { .main = (*(Function_t*)getStackEntry(&functionStack)), .staticVarHolder = staticVariableHolder, .valid = 1 }; + + vecFree(functionStack); + vecFree(stackHistoryHolder); + scriptCurrentLine = 1; + return parse; +} + + +void exitFunction(Operator_t* start, u32 len) { + for (u32 i = 0; i < len; i++) { + if (start[i].token == Variable) { + if (start[i].variable.staticVariableOptionsUnion == 0) { + FREE(start[i].variable.name); + } + + if (start[i].variable.staticVariableType == 2) { + FREE(start[i].variable.stringType); + } + } + else if (start[i].token == BetweenBrackets) { + exitFunction(start[i].variable.betweenBrackets.data, start[i].variable.betweenBrackets.len); + FREE(start[i].variable.betweenBrackets.data); + } + else if (start[i].token == CallArgs) { + CallArgs_t* call = &start[i].callArgs; + + while (call != NULL) { + if (call->extraAction == ActionExtraArrayIndex) { + Function_t* f = call->extra; + exitFunction(f->operations.data, f->operations.count); + vecFree(f->operations); + FREE(f); + } + else if (call->extraAction == ActionExtraMemberName) { + FREE(call->extra); + } + else if (call->extraAction == ActionExtraCallArgs) { + Function_t* f = call->extra; + exitFunction(f->operations.data, f->operations.count); + vecFree(f->operations); + FREE(f); + } + + CallArgs_t* nextCall = call->next; + if (call != &start[i].callArgs) { + FREE(call); + } + + call = nextCall; + } + } + } +} + +void exitStaticVars(Vector_t* v) { + vecForEach(Variable_t*, staticVar, v) { + if (staticVar->variableType == FunctionClass) { + if (!staticVar->function.builtIn) { + exitFunction(staticVar->function.function.operations.data, staticVar->function.function.operations.count); + vecFree(staticVar->function.function.operations); + } + } + else { + freeVariableInternal(staticVar); + } } } \ No newline at end of file diff --git a/source/script/parser.h b/source/script/parser.h index 37c21be..b09bd7a 100644 --- a/source/script/parser.h +++ b/source/script/parser.h @@ -1,6 +1,15 @@ + #pragma once +#include "compat.h" -#include "types.h" +typedef struct { + Function_t main; + Vector_t staticVarHolder; + u8 valid; +} ParserRet_t; -scriptResult_t mainLoop(scriptCtx_t* ctx); -void printError(scriptResult_t res); \ No newline at end of file +#define SCRIPT_PARSER_ERR(message, ...) printScriptError(SCRIPT_PARSER_FATAL, message, ##__VA_ARGS__); return (ParserRet_t){0} + +ParserRet_t parseScript(char* in); +void exitStaticVars(Vector_t* v); +void exitFunction(Operator_t* start, u32 len); \ No newline at end of file diff --git a/source/script/saveClass.c b/source/script/saveClass.c new file mode 100644 index 0000000..bcbc48b --- /dev/null +++ b/source/script/saveClass.c @@ -0,0 +1,30 @@ +#include "saveClass.h" +#include "compat.h" + +u8 oneStringArgSave[] = {StringClass}; + +ClassFunction(readFile){ + Variable_t *arg = (*args); + save_data_file_ctx_t dataArc; + if (!save_open_file(&caller->save->saveCtx, &dataArc, arg->string.value, OPEN_MODE_READ)) + return NULL; + + u64 totalSize; + save_data_file_get_size(&dataArc, &totalSize); + + u8 *buff = malloc(totalSize); + + save_data_file_read(&dataArc, &totalSize, 0, buff, totalSize); + + Variable_t a = {.variableType = ByteArrayClass}; + a.solvedArray.vector = vecFromArray(buff, totalSize, 1); + return copyVariableToPtr(a); +} + +ClassFunctionTableEntry_t saveFunctions[] = { + {"readFile", readFile, 1, oneStringArgSave}, +}; + +Variable_t getSaveMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, saveFunctions, ARRAY_SIZE(saveFunctions)); +} \ No newline at end of file diff --git a/source/script/saveClass.h b/source/script/saveClass.h new file mode 100644 index 0000000..f17f99c --- /dev/null +++ b/source/script/saveClass.h @@ -0,0 +1,4 @@ +#include "model.h" +#include "genericClass.h" + +Variable_t getSaveMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/scriptError.c b/source/script/scriptError.c new file mode 100644 index 0000000..3579060 --- /dev/null +++ b/source/script/scriptError.c @@ -0,0 +1,16 @@ +#include "scriptError.h" +#include "compat.h" +#include + +s64 scriptCurrentLine; + +void printScriptError(u8 errLevel, char* message, ...) { + va_list args; + + va_start(args, message); + gfx_printf("\n\n[%s] ", (errLevel == SCRIPT_FATAL) ? "FATAL" : (errLevel == SCRIPT_PARSER_FATAL) ? "PARSE_FATAL" : "WARN"); + gfx_vprintf(message, args); + if (errLevel < SCRIPT_WARN) + gfx_printf("\nError occured on or near line %d\n", scriptCurrentLine); + va_end(args); +} \ No newline at end of file diff --git a/source/script/scriptError.h b/source/script/scriptError.h new file mode 100644 index 0000000..1bee452 --- /dev/null +++ b/source/script/scriptError.h @@ -0,0 +1,16 @@ +#pragma once +#include "model.h" + +enum { + SCRIPT_FATAL = 0, + SCRIPT_PARSER_FATAL, + SCRIPT_WARN, +}; + +extern s64 scriptCurrentLine; + +void printScriptError(u8 errLevel, char* message, ...); + +#define SCRIPT_FATAL_ERR(message, ...) printScriptError(SCRIPT_FATAL, message, ##__VA_ARGS__); return NULL +#define SCRIPT_WARN_ERR(message, ...) printScriptError(SCRIPT_WARN, message, ##__VA_ARGS__) + diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c new file mode 100644 index 0000000..6d601e0 --- /dev/null +++ b/source/script/standardLibrary.c @@ -0,0 +1,133 @@ +#include "model.h" +#include "compat.h" +#include "genericClass.h" +#include "eval.h" +#include "garbageCollector.h" +#include "intClass.h" +#include "standardLibrary.h" +#include + +#ifndef WIN32 +#include "../storage/mountmanager.h" +#include "../keys/keys.h" +#endif + +ClassFunction(stdIf) { + s64 value = getIntValue(args[0]); + + + if (value) { + Variable_t* res = genericCallDirect(args[1], NULL, 0); + if (res == NULL) + return NULL; + + removePendingReference(res); + } + + return &emptyClass; +} + +// TODO: implement else by making if return a class that is else-able + +ClassFunction(stdWhile) { + Variable_t* result = eval(args[0]->function.function.operations.data, args[0]->function.function.operations.count, 1); + if (result == NULL || result->variableType != IntClass) + return NULL; + + while (result->integer.value) { + removePendingReference(result); + Variable_t* res = genericCallDirect(args[1], NULL, 0); + if (res == NULL) + return NULL; + + removePendingReference(res); + + result = eval(args[0]->function.function.operations.data, args[0]->function.function.operations.count, 1); + if (result == NULL || result->variableType != IntClass) + return NULL; + } + + removePendingReference(result); + + return &emptyClass; +} + +ClassFunction(stdPrint) { + for (int i = 0; i < argsLen; i++) { + Variable_t* res = callMemberFunctionDirect(args[i], "print", NULL, 0); + if (res == NULL) + return NULL; + } + + + return &emptyClass; +} + +ClassFunction(stdExit) { + return NULL; +} + +#ifndef WIN32 +ClassFunction(stdMountSysmmc){ + if (connectMMC(MMC_CONN_EMMC)) + return newIntVariablePtr(1); + + Variable_t *arg = (*args); + if (mountMMCPart(arg->string.value).err) + return newIntVariablePtr(1); // Maybe change for error? + + return newIntVariablePtr(0); +} + +ClassFunction(stdMountSave){ + Variable_t *arg = (*args); + Variable_t var = {.variableType = SaveClass}; + SaveClass_t* save = calloc(1, sizeof(SaveClass_t)); + if (f_open(&save->saveFile, arg->string.value, FA_READ)) + return NULL; + save_init(&save->saveCtx, &save->saveFile, dumpedKeys.save_mac_key, 0); + if (!save_process(&save->saveCtx)) + return NULL; + + var.save = save; + return copyVariableToPtr(var); +} +#else +ClassFunction(stdMountSysmmc){ + return newIntVariablePtr(0); +} +ClassFunction(stdMountSave){ + return newIntVariablePtr(0); +} +#endif + +enum standardFunctionIndexes { + STD_IF = 0, + STD_WHILE, + STD_PRINT, + STD_MOUNTSYSMMC, + STD_MOUNTSAVE, + STD_EXIT, +}; + +u8 oneIntoneFunction[] = { IntClass, FunctionClass }; +u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; +u8 oneStringArgStd[] = {StringClass}; + +ClassFunctionTableEntry_t standardFunctionDefenitions[] = { + [STD_IF] = {"if", stdIf, 2, oneIntoneFunction}, + [STD_WHILE] = {"while", stdWhile, 2, doubleFunctionClass}, + [STD_PRINT] = {"print", stdPrint, VARARGCOUNT, 0}, + [STD_MOUNTSYSMMC] = {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, + [STD_MOUNTSAVE] = {"readsave", stdMountSave, 1, oneStringArgStd}, + [STD_EXIT] = {"exit", stdExit, 0, 0}, +}; + +ClassFunctionTableEntry_t* searchStdLib(char* funcName) { + for (int i = 0; i < ARRAY_SIZE(standardFunctionDefenitions); i++) { + if (!strcmp(funcName, standardFunctionDefenitions[i].name)) + return &standardFunctionDefenitions[i]; + } + + return NULL; +} \ No newline at end of file diff --git a/source/script/standardLibrary.h b/source/script/standardLibrary.h new file mode 100644 index 0000000..6f92c8a --- /dev/null +++ b/source/script/standardLibrary.h @@ -0,0 +1,4 @@ +#pragma once +#include "model.h" + +ClassFunctionTableEntry_t* searchStdLib(char* funcName); \ No newline at end of file diff --git a/source/script/types.h b/source/script/types.h deleted file mode 100644 index e224c94..0000000 --- a/source/script/types.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include -#include "../utils/vector.h" - -enum Tokens { - Invalid = 0, - Variable = 1, - ArrayVariable, - Function, - LBracket, - StrLit, - IntLit, - LSBracket, - VariableAssignment, - ArrayVariableAssignment, - FunctionAssignment, - RBracket, - RCBracket, - LCBracket, - Seperator, - Plus, - Minus, - Multiply, - Division, - Mod, - Smaller, - SmallerEqual, - Bigger, - BiggerEqual, - Equal, - EqualEqual, - Not, - NotEqual, - LogicAND, - LogicOR, - RSBracket, - AND, - OR, - Selector, - BitShiftLeft, - BitShiftRight, - EquationSeperator, -}; - -typedef struct { - u8 token; - union { - char* text; - int val; - }; -} lexarToken_t; - -enum Errors { - ERRBADOPERATOR = 1, - ERRDOUBLENOT, - ERRSYNTAX, - ERRINVALIDTYPE, - ERRNOVAR, - ERRNOFUNC, - ERRINACTIVEINDENT, - ERRDIVBYZERO, - ERRFATALFUNCFAIL, - ERRESCSCRIPT, -}; - -enum Variables { - IntType = 0, - StringType, - IntArrayType, - StringArrayType, - ByteArrayType, - JumpType, - DictType, - NullType, - ErrType, - EmptyArrayType, -}; - -typedef struct { // this is to keep track of how many {} we passed. Keep an internal var with the "indentation level", +1 for {, -1 for }. have an array with the following def on what to do (on func: enter, set indentation & jump back, on while, jump to while, use while as if, on if simply set true or false) - union { - struct { - u8 active : 1; - u8 skip : 1; - u8 jump : 1; - u8 function : 1; - }; - u8 container; - }; - int jumpLoc; -} indentInstructor_t; - -typedef struct { - union { - struct { - u8 varType : 7; - u8 free : 1; - }; - u8 typeUnion; - }; - union { - int integerType; - char* stringType; - Vector_t vectorType; - }; -} Variable_t; - -typedef struct { - char* key; - Variable_t value; -} dict_t; - -typedef struct { - Vector_t indentInstructors; // Type indentInstructor_t - Vector_t varDict; // Type dict_t - Vector_t script; // Type lexarToken_t - u32 startEquation; - u32 curPos; - u8 indentIndex; -} scriptCtx_t; - -typedef Variable_t(*func_int_ptr)(scriptCtx_t* ctx, Variable_t *vars, u32 len); - -typedef struct { - char* key; - func_int_ptr value; - u8 argCount; - u8* typeArray; -} functionStruct_t; - -typedef struct { - int resCode; - lexarToken_t* nearToken; - u32 len; -} scriptResult_t; - - -#define newDict(strName, var) (dict_t) {strName, var} -#define newVar(var, frii, value) (Variable_t) {.varType = var, .free = frii, value} - -#define varArgs 255 - -#define NullVar newVar(NullType, 0, 0) -#define ErrVar(err) newVar(ErrType, 0, err) -#define IntVal(val) newVar(IntType, 0, val) \ No newline at end of file diff --git a/source/script/unsolvedArrayClass.c b/source/script/unsolvedArrayClass.c new file mode 100644 index 0000000..a328c03 --- /dev/null +++ b/source/script/unsolvedArrayClass.c @@ -0,0 +1,187 @@ +#include "unsolvedArrayClass.h" +#include "eval.h" +#include "compat.h" +#include "intClass.h" +#include "scriptError.h" +#include "garbageCollector.h" +#include + +Variable_t* solveArray(Variable_t *unsolvedArray) { + if (unsolvedArray->unsolvedArray.operations.count <= 0) { + return copyVariableToPtr(*unsolvedArray); + // Return empty unsolved array that turns into a solved array once something is put into it + } + + int lasti = 0; + Operator_t* ops = unsolvedArray->unsolvedArray.operations.data; + u8 type = None; + Vector_t v = { 0 }; + + + for (int i = 0; i < unsolvedArray->unsolvedArray.operations.count; i++) { + if (ops[i].token == EquationSeperator || i + 1 == unsolvedArray->unsolvedArray.operations.count) { + if (i + 1 == unsolvedArray->unsolvedArray.operations.count) + i++; + + Variable_t* var = eval(&ops[lasti], i - lasti, 1); + if (var == NULL) + return NULL; + + if (v.data == NULL) { + if (var->variableType == IntClass) { + v = newVec(sizeof(s64), 1); + type = IntClass; + } + else if (var->variableType == StringClass) { + v = newVec(sizeof(char*), 1); + type = StringClass; + } + else { + SCRIPT_FATAL_ERR("Unknown array type"); + } + } + + if (var->variableType == type) { + if (var->variableType == IntClass) { + vecAdd(&v, var->integer.value); + } + else { + char* str = CpyStr(var->string.value); + vecAdd(&v, str); + } + } + else { + SCRIPT_FATAL_ERR("Variable type is not the same as array type"); + } + + removePendingReference(var); + + lasti = i + 1; + } + } + + Variable_t arrayVar = { .variableType = (type == IntClass) ? IntArrayClass : StringArrayClass, .solvedArray.vector = v }; + return copyVariableToPtr(arrayVar); +} + +Variable_t createUnsolvedArrayVariable(Function_t* f) { + Variable_t var = { 0 }; + Vector_t holder = { 0 }; + u8 varType = Invalid; + + // Foreach to attempt to create the array. Should fail if calcs are done or types are not equal + if (f->operations.count > 0) { + vecForEach(Operator_t*, curOp, (&f->operations)) { + if (holder.data == NULL) { + if (curOp->variable.staticVariableType == 1) { + varType = IntClass; + holder = newVec(sizeof(s64), 4); + vecAdd(&holder, (curOp->variable.integerType)); + } + else if (curOp->variable.staticVariableType == 2) { + if (!strcmp(curOp->variable.stringType, "BYTE[]")) { + varType = ByteArrayClass; // Repurpose varType + holder = newVec(sizeof(u8), 4); + FREE(curOp->variable.stringType); + } + else { + varType = StringClass; + holder = newVec(sizeof(char*), 4); + vecAdd(&holder, (curOp->variable.stringType)); + } + } + else { + break; + } + } + else { + if ((curOp - 1)->token == EquationSeperator && curOp->token == Variable) { + if (curOp->variable.staticVariableType == 1) { + if (varType == IntClass) { + vecAdd(&holder, curOp->variable.integerType); + } + else if (varType == ByteArrayClass) { + u8 var = (u8)(curOp->variable.integerType & 0xFF); + vecAdd(&holder, var); + } + } + else if (curOp->variable.staticVariableType == 2) { + if (varType == StringClass) { + vecAdd(&holder, curOp->variable.stringType); + } + } + else { + vecFree(holder); + holder.data = NULL; + break; + } + } + else if (curOp->token == EquationSeperator) { + continue; + } + else { + vecFree(holder); + holder.data = NULL; + break; + } + } + } + } + + if (varType != Invalid) { + if (varType == IntClass) { + var.variableType = IntArrayClass; + } + else if (varType == StringClass) { + var.variableType = StringArrayClass; + } + else { + var.variableType = varType; + } + + vecFree(f->operations); + var.solvedArray.vector = holder; + var.readOnly = 1; + } + else { + var.unsolvedArray.operations = f->operations; + var.variableType = UnresolvedArrayClass; + } + + + return var; +} + +u8 anotherOneVarArg[] = { VARARGCOUNT }; + +ClassFunction(createTypedArray) { + Vector_t v = { 0 }; + Variable_t* arg = *args; + + if (arg->variableType == IntClass) { + v = newVec(sizeof(s64), 1); + vecAdd(&v, arg->integer.value); + } + else if (arg->variableType == StringClass) { + v = newVec(sizeof(char*), 1); + char* str = CpyStr(arg->string.value); + vecAdd(&v, str); + } + else { + SCRIPT_FATAL_ERR("Unknown array type"); + } + + Variable_t arrayVar = { .variableType = (arg->variableType == IntClass) ? IntArrayClass : StringArrayClass, .solvedArray.vector = v }; + *caller = arrayVar; + + return &emptyClass; +} + +ClassFunctionTableEntry_t unsolvedArrayFunctions[] = { + {"+", createTypedArray, 1, anotherOneVarArg}, + {"add", createTypedArray, 1, anotherOneVarArg}, +}; + +Variable_t getUnsolvedArrayMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, unsolvedArrayFunctions, ARRAY_SIZE(unsolvedArrayFunctions)); +} \ No newline at end of file diff --git a/source/script/unsolvedArrayClass.h b/source/script/unsolvedArrayClass.h new file mode 100644 index 0000000..557adf8 --- /dev/null +++ b/source/script/unsolvedArrayClass.h @@ -0,0 +1,8 @@ +#pragma once +#include "model.h" +#include "genericClass.h" +#include "compat.h" + +Variable_t createUnsolvedArrayVariable(Function_t* f); +Variable_t* solveArray(Variable_t* unsolvedArray); +Variable_t getUnsolvedArrayMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/variables.c b/source/script/variables.c deleted file mode 100644 index ed3c2a5..0000000 --- a/source/script/variables.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "variables.h" -#include "types.h" -#include -#include - -void freeVariable(Variable_t dv) { - if (!dv.free) - return; - - switch (dv.varType) { - case StringType: - FREE(dv.stringType); - break; - - case StringArrayType:; - char** strArray = vecGetArray(char**, dv.vectorType); - for (u32 i = 0; i < dv.vectorType.count; i++){ - free(strArray[i]); - } - - case IntArrayType: - case ByteArrayType: - vecFree(dv.vectorType); - break; - } -} - -void freeVariableVector(Vector_t *v) { - Variable_t* vars = vecGetArrayPtr(v, Variable_t*); - for (int i = 0; i < v->count; i++) { - freeVariable(vars[i]); - } - vecFreePtr(v); -} - -void freeDictVector(Vector_t *v) { - dict_t* dic = vecGetArrayPtr(v, dict_t*); - for (int i = 0; i < v->count; i++) { - FREE(dic[i].key); - freeVariable(dic[i].value); - } - vecFreePtr(v); -} - -Variable_t* dictVectorFind(Vector_t* v, const char* key) { - dict_t* dic = vecGetArrayPtr(v, dict_t*); - for (int i = 0; i < v->count; i++) { - if (!strcmp(dic[i].key, key)) - return &dic[i].value; - } - - return NULL; -} - -void dictVectorAdd(Vector_t* v, dict_t add) { - if (add.key == NULL) - return; - - Variable_t* var = dictVectorFind(v, add.key); - - if (var != NULL) { - if ((var->varType >= StringType && var->varType <= ByteArrayType && var->varType == add.value.varType) && (add.value.stringType == var->stringType || add.value.vectorType.data == var->vectorType.data)) - return; - - freeVariable(*var); - *var = add.value; - free(add.key); - return; - } - else { - vecAddElement(v, add); - } -} - -scriptCtx_t createScriptCtx() { - scriptCtx_t s = { - .indentInstructors = newVec(sizeof(indentInstructor_t), 64), - .varDict = newVec(sizeof(dict_t), 8), - .startEquation = 0, - .curPos = 0 - }; - return s; -} - -// We should rewrite this to actually use the vector! -u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, u8 func, int jumpLoc) { - if (level >= 64) - return 1; - - indentInstructor_t* instructors = vecGetArray(indentInstructor_t*, ctx->indentInstructors); - indentInstructor_t* instructor = &instructors[level]; - - instructor->skip = skip; - instructor->active = 1; - instructor->function = func; - instructor->jump = (jumpLoc >= 0) ? 1 : 0; - instructor->jumpLoc = jumpLoc; - - return 0; -} - -indentInstructor_t* getCurIndentInstruction(scriptCtx_t* ctx) { - indentInstructor_t* instructors = vecGetArray(indentInstructor_t*, ctx->indentInstructors); - return &instructors[ctx->indentIndex]; -} \ No newline at end of file diff --git a/source/script/variables.h b/source/script/variables.h deleted file mode 100644 index dac6115..0000000 --- a/source/script/variables.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "types.h" - -void dictVectorAdd(Vector_t* v, dict_t add); -Variable_t* dictVectorFind(Vector_t* v, const char* key); -void freeDictVector(Vector_t* v); -void freeVariableVector(Vector_t* v); -void freeVariable(Variable_t dv); -scriptCtx_t createScriptCtx(); - -u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, u8 func, int jumpLoc); -indentInstructor_t* getCurIndentInstruction(scriptCtx_t* ctx); - -static inline u8 setCurIndentInstruction(scriptCtx_t* ctx, u8 skip, u8 func, int jumpLoc) { - return setIndentInstruction(ctx, ctx->indentIndex, skip, func, jumpLoc); -} \ No newline at end of file diff --git a/source/script/vector.c b/source/script/vector.c new file mode 100644 index 0000000..b1a09ab --- /dev/null +++ b/source/script/vector.c @@ -0,0 +1,111 @@ +#ifdef WIN32 +#include "vector.h" +#include +#include +#include + +Vector_t newVec(u8 typesz, u32 preallocate) { + if (preallocate) { + Vector_t res = { + .data = calloc(preallocate, typesz), + .capacity = preallocate * typesz, + .count = 0, + .elemSz = typesz + }; + + // check .data != null; + return res; + } + else { + Vector_t res = { + .data = NULL, + .capacity = 1 * typesz, + .count = 0, + .elemSz = typesz + }; + + return res; + } +} + +Vector_t vecFromArray(void* array, u32 count, u32 typesz) +{ + Vector_t res = { + .data = array, + .capacity = count * typesz, + .count = count, + .elemSz = typesz + }; + return res; +} + +int vecAddElem(Vector_t* v, void* elem, u8 sz) { + if (!v || !elem || v->elemSz != sz) + return 0; + + if (v->data == NULL) { + v->data = calloc(1, v->elemSz); + } + + u32 usedbytes = v->count * sz; + if (usedbytes >= v->capacity) + { + if (v->capacity > 5000) { + printf("uhhhh"); + } + v->capacity *= 2; + void* buff = malloc(v->capacity); + if (!buff) + return 0; + memcpy(buff, v->data, v->capacity / 2); + free(v->data); + v->data = buff; + } + + memcpy((char*)v->data + usedbytes, elem, sz); + v->count++; + return 1; +} + +Vector_t vecCopyOffset(Vector_t* orig, u32 offset) { + Vector_t dst = newVec(orig->elemSz, orig->count - offset); + memcpy(dst.data, ((u8*)orig->data + orig->elemSz * offset), (orig->count - offset) * orig->elemSz); + dst.count = orig->count - offset; + return dst; +} + +Vector_t vecCopy(Vector_t* orig) { + return vecCopyOffset(orig, 0); +} + + +void* getStackEntry(Vector_t *stack) { + if (stack->count <= 0) + return NULL; + + return ((u8*)stack->data + (stack->elemSz * (stack->count - 1))); +} + +// This will stay valid until the queue is modified +void* popStackEntry(Vector_t* stack) { + if (stack->count <= 0) + return NULL; + + void* a = getStackEntry(stack); + stack->count--; + return a; +} + +void vecRem(Vector_t *vec, int idx) { + if (vec->count <= 0 || idx >= vec->count) + return; + + if (idx == (vec->count - 1)) { + vec->count--; + return; + } + + memcpy((u8*)vec->data + (vec->elemSz * idx), (u8*)vec->data + (vec->elemSz * (idx + 1)), (vec->count - idx - 1) * vec->elemSz); + vec->count--; +} +#endif \ No newline at end of file diff --git a/source/script/vector.h b/source/script/vector.h new file mode 100644 index 0000000..5e2681d --- /dev/null +++ b/source/script/vector.h @@ -0,0 +1,24 @@ +#ifdef WIN32 +#pragma once + +#include "model.h" + +int vecAddElem(Vector_t* v, void* elem, u8 sz); +Vector_t newVec(u8 typesz, u32 preallocate); +Vector_t vecCopy(Vector_t* orig); +Vector_t vecCopyOffset(Vector_t* orig, u32 offset); +Vector_t vecFromArray(void* array, u32 count, u32 typesz); + +#define vecAdd(vec, element) vecAddElem(vec, &element, sizeof(element)) +#define vecGetArrayPtr(vec, type) (type)(vec)->data +#define vecGetArray(vec, type) (type)(vec).data +#define vecFreePtr(vec) FREE(vec->data) +#define vecFree(vec) FREE(vec.data) +#define vecGetCapacity(vec) (vec.capacity / vec.elemSz) + +#define vecForEach(type, varname, vecPtr) for (type varname = vecPtr->data; ((u8*)varname - (u8*)vecPtr->data) < (vecPtr->count * vecPtr->elemSz); varname++) + +void* getStackEntry(Vector_t* stack); +void* popStackEntry(Vector_t* stack); +void vecRem(Vector_t * vec, int idx); +#endif \ No newline at end of file diff --git a/source/utils/vector.c b/source/utils/vector.c index 900e1f8..cb8f246 100644 --- a/source/utils/vector.c +++ b/source/utils/vector.c @@ -1,4 +1,5 @@ #include "vector.h" +#include "../gfx/gfx.h" #include #include @@ -44,8 +45,7 @@ int _vecAdd(Vector_t* v, void* elem, u8 sz) { if (v->data == NULL) { v->data = calloc(1, v->elemSz); } - - u32 usedbytes = v->count * sz; + u32 usedbytes = v->count * (u32)v->elemSz; if (usedbytes >= v->capacity) { v->capacity *= 2; @@ -56,8 +56,7 @@ int _vecAdd(Vector_t* v, void* elem, u8 sz) { free(v->data); v->data = buff; } - - memcpy((char*)v->data + usedbytes, elem, sz); + memcpy(((u8*)v->data) + usedbytes, elem, v->elemSz); v->count++; return 1; } diff --git a/source/utils/vector.h b/source/utils/vector.h index cefbfe0..9fcb1d0 100644 --- a/source/utils/vector.h +++ b/source/utils/vector.h @@ -1,6 +1,8 @@ #pragma once #include +#pragma pack(1) + typedef struct { void* data; u32 capacity; @@ -9,6 +11,8 @@ typedef struct { // u32 typeTag; } Vector_t; +#pragma pack() + #define FREE(x) free(x); x = NULL; #define vecAddElem(v, elem) _vecAdd(v, &elem, sizeof(elem))