From 2ddc7ae2a9e196def42d4902262f32ae69e15883 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 9 Jul 2021 22:56:13 +0200 Subject: [PATCH 01/62] tsv3 start ig --- .gitignore | 4 + source/fs/menus/filemenu.c | 34 +- source/fs/menus/foldermenu.c | 3 - source/main.c | 4 +- source/script/ABadIdeaVersion3.c | 91 +++ source/script/ABadIdeaVersion3.vcxproj | 182 +++++ .../script/ABadIdeaVersion3.vcxproj.filters | 135 ++++ source/script/ABadIdeaVersion3.vcxproj.user | 4 + source/script/StringClass.c | 60 ++ source/script/StringClass.h | 10 + source/script/args.c | 502 ------------ source/script/args.h | 7 - source/script/arrayClass.c | 259 +++++++ source/script/arrayClass.h | 5 + source/script/arrayReferenceClass.c | 24 + source/script/arrayReferenceClass.h | 5 + source/script/compat.h | 21 + source/script/dictionaryClass.h | 3 + source/script/eval.c | 266 +++++++ source/script/eval.h | 19 + source/script/functionClass.c | 67 ++ source/script/functionClass.h | 8 + source/script/functions.c | 529 ------------- source/script/functions.h | 4 - source/script/garbageCollector.c | 122 +++ source/script/garbageCollector.h | 12 + source/script/genericClass.c | 264 +++++++ source/script/genericClass.h | 25 + source/script/intClass.c | 76 ++ source/script/intClass.h | 13 + source/script/lexer.c | 308 -------- source/script/lexer.h | 6 - source/script/model.c | 43 ++ source/script/model.h | 269 +++++++ source/script/parser.c | 728 +++++++++++++++--- source/script/parser.h | 15 +- source/script/saveClass.c | 30 + source/script/saveClass.h | 4 + source/script/scriptError.c | 16 + source/script/scriptError.h | 16 + source/script/standardLibrary.c | 133 ++++ source/script/standardLibrary.h | 4 + source/script/types.h | 145 ---- source/script/unsolvedArrayClass.c | 187 +++++ source/script/unsolvedArrayClass.h | 8 + source/script/variables.c | 105 --- source/script/variables.h | 16 - source/script/vector.c | 111 +++ source/script/vector.h | 24 + source/utils/vector.c | 7 +- source/utils/vector.h | 4 + 51 files changed, 3188 insertions(+), 1749 deletions(-) create mode 100644 source/script/ABadIdeaVersion3.c create mode 100644 source/script/ABadIdeaVersion3.vcxproj create mode 100644 source/script/ABadIdeaVersion3.vcxproj.filters create mode 100644 source/script/ABadIdeaVersion3.vcxproj.user create mode 100644 source/script/StringClass.c create mode 100644 source/script/StringClass.h delete mode 100644 source/script/args.c delete mode 100644 source/script/args.h create mode 100644 source/script/arrayClass.c create mode 100644 source/script/arrayClass.h create mode 100644 source/script/arrayReferenceClass.c create mode 100644 source/script/arrayReferenceClass.h create mode 100644 source/script/compat.h create mode 100644 source/script/dictionaryClass.h create mode 100644 source/script/eval.c create mode 100644 source/script/eval.h create mode 100644 source/script/functionClass.c create mode 100644 source/script/functionClass.h delete mode 100644 source/script/functions.c delete mode 100644 source/script/functions.h create mode 100644 source/script/garbageCollector.c create mode 100644 source/script/garbageCollector.h create mode 100644 source/script/genericClass.c create mode 100644 source/script/genericClass.h create mode 100644 source/script/intClass.c create mode 100644 source/script/intClass.h delete mode 100644 source/script/lexer.c delete mode 100644 source/script/lexer.h create mode 100644 source/script/model.c create mode 100644 source/script/model.h create mode 100644 source/script/saveClass.c create mode 100644 source/script/saveClass.h create mode 100644 source/script/scriptError.c create mode 100644 source/script/scriptError.h create mode 100644 source/script/standardLibrary.c create mode 100644 source/script/standardLibrary.h delete mode 100644 source/script/types.h create mode 100644 source/script/unsolvedArrayClass.c create mode 100644 source/script/unsolvedArrayClass.h delete mode 100644 source/script/variables.c delete mode 100644 source/script/variables.h create mode 100644 source/script/vector.c create mode 100644 source/script/vector.h 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)) From 623634b5157191888d2f2f773adfc988bec0d4c0 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 9 Jul 2021 23:19:10 +0200 Subject: [PATCH 02/62] optimize arrayClass.c --- source/script/arrayClass.c | 118 +++++++++++++++---------------------- 1 file changed, 47 insertions(+), 71 deletions(-) diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index 14be54f..a7b7d28 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -11,6 +11,7 @@ u8 anotherOneIntArg[] = { IntClass }; u8 oneStringoneFunction[] = { StringClass, FunctionClass }; +u8 doubleInt[] = {IntClass, IntClass}; u8 oneIntOneAny[] = { IntClass, VARARGCOUNT }; u8 anotherAnotherOneVarArg[] = { VARARGCOUNT }; u8 oneByteArrayClass[] = {ByteArrayClass}; @@ -36,6 +37,34 @@ Variable_t arrayClassGetIdx(Variable_t *caller, s64 idx) { return (Variable_t) { 0 }; } +int arrayClassAdd(Variable_t *caller, Variable_t *add){ + if (caller->variableType == IntArrayClass) { + if (add->variableType != IntClass) { + return 1; + } + + vecAdd(&caller->solvedArray.vector, add->integer.value); + } + else if (caller->variableType == StringArrayClass) { + if (add->variableType != StringClass) { + return 1; + } + + char* str = CpyStr(add->string.value); + vecAdd(&caller->solvedArray.vector, str); + } + else if (caller->variableType == ByteArrayClass) { + if (add->variableType != IntClass) { + return 1; + } + + u8 val = (u8)(add->integer.value & 0xFF); + vecAdd(&caller->solvedArray.vector, val); + } + + return 0; +} + ClassFunction(getArrayIdx) { s64 getVal = (*args)->integer.value; // Out of bounds @@ -53,35 +82,22 @@ ClassFunction(getArrayLen) { return newIntVariablePtr(caller->solvedArray.vector.count); } -ClassFunction(createRefSkip) { +ClassFunction(arraySlice) { 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); + s64 takeAmount = getIntValue(args[1]); + + if (caller->solvedArray.vector.count < (skipAmount + takeAmount) || skipAmount <= 0 || takeAmount <= 0) { + SCRIPT_FATAL_ERR("Slicing out of range of array with len %d", (int)caller->solvedArray.vector.count); } Variable_t refSkip = { .variableType = SolvedArrayReferenceClass }; refSkip.solvedArray.arrayClassReference = caller; refSkip.solvedArray.offset = skipAmount; - refSkip.solvedArray.len = caller->solvedArray.vector.count - skipAmount; + refSkip.solvedArray.len = takeAmount; 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; @@ -112,39 +128,16 @@ ClassFunction(arrayCopy) { ClassFunction(arraySet) { s64 idx = getIntValue(*args); Vector_t* v = &caller->solvedArray.vector; - if (v->count < idx || idx <= 0) { + 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); + u32 oldCount = caller->solvedArray.vector.count; + caller->solvedArray.vector.count = idx; + if (arrayClassAdd(caller, args[1])){ + SCRIPT_FATAL_ERR("Adding the wrong type to a typed array"); } + caller->solvedArray.vector.count = oldCount; return &emptyClass; } @@ -152,28 +145,12 @@ ClassFunction(arraySet) { 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); + if (caller->readOnly) { + SCRIPT_FATAL_ERR("Array is read-only"); } - 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); + if (arrayClassAdd(caller, arg)){ + SCRIPT_FATAL_ERR("Adding the wrong type to a typed array"); } return &emptyClass; @@ -219,7 +196,7 @@ ClassFunction(arrayMinus) { ClassFunction(bytesToStr) { if (caller->variableType != ByteArrayClass) { - SCRIPT_FATAL_ERR("Nedd a bytearray to convert to str"); + SCRIPT_FATAL_ERR("Need a bytearray to convert to str"); } char* buff = malloc(caller->solvedArray.vector.count + 1); @@ -241,13 +218,12 @@ ClassFunction(eqArray){ ClassFunctionTableEntry_t arrayFunctions[] = { {"get", getArrayIdx, 1, anotherOneIntArg }, {"len", getArrayLen, 0, 0}, - {"skip", createRefSkip, 1, anotherOneIntArg}, + {"slice", arraySlice, 2, doubleInt}, {"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}, From 65a28d8ef61e9c05d960f0143ed969b998c5a17f Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 9 Jul 2021 23:46:21 +0200 Subject: [PATCH 03/62] implement if.else() --- source/script/ABadIdeaVersion3.vcxproj | 2 ++ .../script/ABadIdeaVersion3.vcxproj.filters | 9 ++++++++ source/script/else.c | 22 +++++++++++++++++++ source/script/else.h | 7 ++++++ source/script/genericClass.c | 2 ++ source/script/model.h | 1 + source/script/parser.c | 14 +++++++----- source/script/standardLibrary.c | 8 +++---- 8 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 source/script/else.c create mode 100644 source/script/else.h diff --git a/source/script/ABadIdeaVersion3.vcxproj b/source/script/ABadIdeaVersion3.vcxproj index c34bbfa..2deb8e2 100644 --- a/source/script/ABadIdeaVersion3.vcxproj +++ b/source/script/ABadIdeaVersion3.vcxproj @@ -145,6 +145,7 @@ + @@ -163,6 +164,7 @@ + diff --git a/source/script/ABadIdeaVersion3.vcxproj.filters b/source/script/ABadIdeaVersion3.vcxproj.filters index 490e559..b6dfa81 100644 --- a/source/script/ABadIdeaVersion3.vcxproj.filters +++ b/source/script/ABadIdeaVersion3.vcxproj.filters @@ -34,6 +34,9 @@ {64738969-63b9-4d0e-85b9-d9a63a7e36b3} + + {ba83a808-23f1-44c6-85e4-d0c6c77200fa} + @@ -81,6 +84,9 @@ Source Files + + Source Files\Classes\Elseable + @@ -131,5 +137,8 @@ Header Files + + Source Files\Classes\Elseable + \ No newline at end of file diff --git a/source/script/else.c b/source/script/else.c new file mode 100644 index 0000000..dca9498 --- /dev/null +++ b/source/script/else.c @@ -0,0 +1,22 @@ +#include "else.h" + +ClassFunction(scriptElse) { + if (!caller->integer.value) { + Variable_t* res = genericCallDirect(args[0], NULL, 0); + if (res == NULL) + return NULL; + + removePendingReference(res); + } + return &emptyClass; +} + +u8 elseOneFunction[] = { FunctionClass }; + +ClassFunctionTableEntry_t elseFunctions[] = { + {"else", scriptElse, 1, elseOneFunction}, +}; + +Variable_t getElseMember(Variable_t* var, char* memberName) { + return getGenericFunctionMember(var, memberName, elseFunctions, ARRAY_SIZE(elseFunctions)); +} \ No newline at end of file diff --git a/source/script/else.h b/source/script/else.h new file mode 100644 index 0000000..170e7be --- /dev/null +++ b/source/script/else.h @@ -0,0 +1,7 @@ +#pragma once +#include "model.h" +#include "genericClass.h" +#include "compat.h" +#include "garbageCollector.h" + +Variable_t getElseMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 0f344e2..02334f0 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -12,6 +12,7 @@ #include "scriptError.h" #include "saveClass.h" #include "unsolvedArrayClass.h" +#include "else.h" Variable_t* copyVariableToPtr(Variable_t var) { Variable_t* a = malloc(sizeof(Variable_t)); @@ -28,6 +29,7 @@ MemberGetters_t memberGetters[] = { {ByteArrayClass, getArrayMember}, {SolvedArrayReferenceClass, getArrayReferenceMember}, {UnresolvedArrayClass, getUnsolvedArrayMember}, + {ElseClass, getElseMember}, #ifndef WIN32 {SaveClass, getSaveMember}, #endif diff --git a/source/script/model.h b/source/script/model.h index c6fe409..2faaaef 100644 --- a/source/script/model.h +++ b/source/script/model.h @@ -35,6 +35,7 @@ typedef enum { EmptyClass, SolvedArrayReferenceClass, SaveClass, + ElseClass, } VariableType_t; typedef enum { diff --git a/source/script/parser.c b/source/script/parser.c index fe24daf..f49f931 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -389,15 +389,17 @@ ParserRet_t parseScript(char* in) { SCRIPT_PARSER_ERR("GET variable before {}"); continue; } - + + // Set last arg to {} 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; + if (funcArgs->operations.count != 0) { + op.token = EquationSeperator; + op.lineNumber = lineNumber; + vecAdd(&funcArgs->operations, op); + op.token = Variable; + } Variable_t a = newFunctionVariable(createFunctionClass(*popFunc, NULL)); vecAdd(&staticVariableHolder, a); diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 6d601e0..0077caf 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -15,7 +15,6 @@ ClassFunction(stdIf) { s64 value = getIntValue(args[0]); - if (value) { Variable_t* res = genericCallDirect(args[1], NULL, 0); if (res == NULL) @@ -24,10 +23,11 @@ ClassFunction(stdIf) { removePendingReference(res); } - return &emptyClass; -} + Variable_t* ret = newIntVariablePtr(value); + ret->variableType = ElseClass; -// TODO: implement else by making if return a class that is else-able + return ret; +} ClassFunction(stdWhile) { Variable_t* result = eval(args[0]->function.function.operations.data, args[0]->function.function.operations.count, 1); From 91af9b4437bdfabb73ffd32833069e5148edb0b9 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 10 Jul 2021 01:12:39 +0200 Subject: [PATCH 04/62] make the garbage collector less terrible --- source/script/StringClass.c | 11 +++++++++++ source/script/arrayClass.c | 7 ++++++- source/script/eval.c | 4 ++++ source/script/garbageCollector.c | 18 ++++++++++++++++++ source/script/genericClass.c | 2 ++ source/script/model.h | 1 + 6 files changed, 42 insertions(+), 1 deletion(-) diff --git a/source/script/StringClass.c b/source/script/StringClass.c index 1de459e..c534d46 100644 --- a/source/script/StringClass.c +++ b/source/script/StringClass.c @@ -47,12 +47,23 @@ ClassFunction(getStringLength) { return newIntVariablePtr(strlen(s1)); } +ClassFunction(stringBytes) { + Variable_t v = { 0 }; + v.variableType = ByteArrayClass; + u32 len = strlen(caller->string.value); + v.solvedArray.vector = newVec(1, len); + v.solvedArray.vector.count = len; + memcpy(v.solvedArray.vector.data, caller->string.value, len); + return copyVariableToPtr(v); +} + u8 oneStringArg[] = { StringClass }; ClassFunctionTableEntry_t stringFunctions[] = { {"print", printStringVariable, 0, 0}, {"+", addStringVariables, 1, oneStringArg }, {"len", getStringLength, 0, 0}, + {"bytes", stringBytes, 0, 0}, }; Variable_t getStringMember(Variable_t* var, char* memberName) { diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index a7b7d28..21e3b3c 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -98,23 +98,28 @@ ClassFunction(arraySlice) { return copyVariableToPtr(refSkip); } +// TODO: arrayForEach does not like the new garbage collector ClassFunction(arrayForEach) { Vector_t* v = &caller->solvedArray.vector; Callback_SetVar_t setVar = { .isTopLevel = 1, .varName = (*args)->string.value }; Variable_t* iter = NULL; iter = copyVariableToPtr(newIntVariable(0)); - + iter->gcDoNotFree = 1; runtimeVariableEdit(&setVar, iter); for (int i = 0; i < v->count; i++) { *iter = arrayClassGetIdx(caller, i); + iter->gcDoNotFree = 1; Variable_t* res = genericCallDirect(args[1], NULL, 0); if (res == NULL) return NULL; } + iter->reference = 1; + free(iter); + return &emptyClass; } diff --git a/source/script/eval.c b/source/script/eval.c index 747a2e2..41a6f46 100644 --- a/source/script/eval.c +++ b/source/script/eval.c @@ -69,6 +69,10 @@ Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback) { else if (op->variable.staticVariableType == 3) { var = copyVariableToPtr(newFunctionVariable(createFunctionClass((Function_t) { 0 }, op->variable.staticFunction))); var->reference = 1; + + if (!strcmp(var->function.builtInPtr->name,"while")) { + var->function.firstArgAsFunction = 1; + } } } else { diff --git a/source/script/garbageCollector.c b/source/script/garbageCollector.c index a0f51b1..0eaca3b 100644 --- a/source/script/garbageCollector.c +++ b/source/script/garbageCollector.c @@ -24,6 +24,23 @@ void modReference(Variable_t* ref, u8 add) { if (ref == NULL || ref->gcDoNotFree) return; + if (add) { + ref->tagCount++; + } + else { + ref->tagCount--; + if (ref->tagCount <= 0) { + if (ref->variableType == FunctionClass && ref->function.builtIn && ref->function.origin != NULL) + modReference(ref->function.origin, 0); + + if (ref->variableType == SolvedArrayReferenceClass) + modReference(ref->solvedArray.arrayClassReference, 0); + + freeVariable(&ref); + } + } + + /* ReferenceCounter_t* additionalFree = NULL; vecForEach(ReferenceCounter_t*, references, (&storedReferences)) { @@ -59,6 +76,7 @@ void modReference(Variable_t* ref, u8 add) { ReferenceCounter_t r = { .ref = ref, .refCount = 1 }; vecAdd(&storedReferences, r); + */ } /* void addPendingReference(Variable_t* ref) { diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 02334f0..56f082e 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -17,6 +17,7 @@ Variable_t* copyVariableToPtr(Variable_t var) { Variable_t* a = malloc(sizeof(Variable_t)); *a = var; + a->tagCount = 0; addPendingReference(a); return a; } @@ -201,6 +202,7 @@ Variable_t getGenericFunctionMember(Variable_t* var, char* memberName, ClassFunc } } + printScriptError(SCRIPT_FATAL, "Could not find member of class"); return (Variable_t){ 0 }; } diff --git a/source/script/model.h b/source/script/model.h index 2faaaef..db004aa 100644 --- a/source/script/model.h +++ b/source/script/model.h @@ -185,6 +185,7 @@ typedef struct _Variable_t { u8 gcDoNotFree : 1; }; }; + u8 tagCount; } Variable_t; typedef struct _CallArgs_t { From 0bef41c0338e3532d058a576099610ea813ef377 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 10 Jul 2021 14:45:09 +0200 Subject: [PATCH 05/62] add break --- source/script/arrayClass.c | 10 ++++++++-- source/script/parser.c | 1 - source/script/scriptError.c | 3 ++- source/script/scriptError.h | 2 ++ source/script/standardLibrary.c | 18 ++++++++++++++++-- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index 21e3b3c..4a37057 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -113,8 +113,14 @@ ClassFunction(arrayForEach) { iter->gcDoNotFree = 1; Variable_t* res = genericCallDirect(args[1], NULL, 0); - if (res == NULL) - return NULL; + if (res == NULL) { + if (scriptLastError == SCRIPT_BREAK) { + break; + } + else { + return NULL; + } + } } iter->reference = 1; diff --git a/source/script/parser.c b/source/script/parser.c index f49f931..359c996 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -420,7 +420,6 @@ ParserRet_t parseScript(char* in) { op.token = EquationSeperator; op.lineNumber = lineNumber; - vecAdd(&lastFunc->operations, op); } else { SCRIPT_PARSER_ERR("Stack count is 1 or state is not a function"); diff --git a/source/script/scriptError.c b/source/script/scriptError.c index 3579060..e85ee98 100644 --- a/source/script/scriptError.c +++ b/source/script/scriptError.c @@ -3,10 +3,11 @@ #include s64 scriptCurrentLine; +u8 scriptLastError = 0; void printScriptError(u8 errLevel, char* message, ...) { va_list args; - + scriptLastError = errLevel; va_start(args, message); gfx_printf("\n\n[%s] ", (errLevel == SCRIPT_FATAL) ? "FATAL" : (errLevel == SCRIPT_PARSER_FATAL) ? "PARSE_FATAL" : "WARN"); gfx_vprintf(message, args); diff --git a/source/script/scriptError.h b/source/script/scriptError.h index 1bee452..161c55f 100644 --- a/source/script/scriptError.h +++ b/source/script/scriptError.h @@ -5,9 +5,11 @@ enum { SCRIPT_FATAL = 0, SCRIPT_PARSER_FATAL, SCRIPT_WARN, + SCRIPT_BREAK, }; extern s64 scriptCurrentLine; +extern u8 scriptLastError; void printScriptError(u8 errLevel, char* message, ...); diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 0077caf..084f57d 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -5,6 +5,7 @@ #include "garbageCollector.h" #include "intClass.h" #include "standardLibrary.h" +#include "scriptError.h" #include #ifndef WIN32 @@ -37,8 +38,14 @@ ClassFunction(stdWhile) { while (result->integer.value) { removePendingReference(result); Variable_t* res = genericCallDirect(args[1], NULL, 0); - if (res == NULL) - return NULL; + if (res == NULL) { + if (scriptLastError == SCRIPT_BREAK) { + break; + } + else { + return NULL; + } + } removePendingReference(res); @@ -67,6 +74,11 @@ ClassFunction(stdExit) { return NULL; } +ClassFunction(stdBreak) { + scriptLastError = SCRIPT_BREAK; + return NULL; +} + #ifndef WIN32 ClassFunction(stdMountSysmmc){ if (connectMMC(MMC_CONN_EMMC)) @@ -108,6 +120,7 @@ enum standardFunctionIndexes { STD_MOUNTSYSMMC, STD_MOUNTSAVE, STD_EXIT, + STD_BREAK, }; u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -121,6 +134,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { [STD_MOUNTSYSMMC] = {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, [STD_MOUNTSAVE] = {"readsave", stdMountSave, 1, oneStringArgStd}, [STD_EXIT] = {"exit", stdExit, 0, 0}, + [STD_BREAK] = {"break", stdBreak, 0, 0}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { From 8c6e70b63dcb40c3515daaf48fc2317bf99b81b4 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 12 Jul 2021 18:04:52 +0200 Subject: [PATCH 06/62] add dicts --- source/script/ABadIdeaVersion3.vcxproj | 1 + .../script/ABadIdeaVersion3.vcxproj.filters | 3 ++ source/script/dictionaryClass.c | 50 +++++++++++++++++++ source/script/dictionaryClass.h | 3 ++ source/script/eval.c | 3 ++ source/script/genericClass.c | 29 +++++++++-- source/script/model.h | 2 + source/script/standardLibrary.c | 9 ++++ 8 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 source/script/dictionaryClass.c diff --git a/source/script/ABadIdeaVersion3.vcxproj b/source/script/ABadIdeaVersion3.vcxproj index 2deb8e2..53eb1d3 100644 --- a/source/script/ABadIdeaVersion3.vcxproj +++ b/source/script/ABadIdeaVersion3.vcxproj @@ -145,6 +145,7 @@ + diff --git a/source/script/ABadIdeaVersion3.vcxproj.filters b/source/script/ABadIdeaVersion3.vcxproj.filters index b6dfa81..26caa24 100644 --- a/source/script/ABadIdeaVersion3.vcxproj.filters +++ b/source/script/ABadIdeaVersion3.vcxproj.filters @@ -87,6 +87,9 @@ Source Files\Classes\Elseable + + Source Files\Classes\Dictionary + diff --git a/source/script/dictionaryClass.c b/source/script/dictionaryClass.c new file mode 100644 index 0000000..242b141 --- /dev/null +++ b/source/script/dictionaryClass.c @@ -0,0 +1,50 @@ +#include "dictionaryClass.h" +#include +#include "garbageCollector.h" + +u8 dictOneStrOneAll[] = { StringClass, VARARGCOUNT }; + +Dict_t* getEntry(Vector_t *v, char* name) { + vecForEach(Dict_t*, dict, v) { + if (!strcmp(name, dict->name)) { + return dict; + } + } + return NULL; +} + +ClassFunction(dictSet) { + addPendingReference(args[1]); + char* arg = CpyStr(args[0]->string.value); + Dict_t* possibleEntry = getEntry(&caller->dictionary.vector, arg); + if (possibleEntry == NULL) { + Dict_t a = { .name = arg, .var = args[1] }; + vecAdd(&caller->dictionary.vector, a); + } + else { + possibleEntry->var = args[1]; + free(arg); + } + return &emptyClass; +} + +ClassFunctionTableEntry_t dictFunctions[] = { + {"set", dictSet, 2, dictOneStrOneAll}, +}; + +Variable_t getDictMember(Variable_t* var, char* memberName) { + if (!strcmp(memberName, "set")) + return getGenericFunctionMember(var, memberName, dictFunctions, ARRAY_SIZE(dictFunctions)); + + vecForEach(Dict_t*, dict, (&var->dictionary.vector)) { + if (!strcmp(dict->name, memberName)) { + Variable_t a = { 0 }; + a.variableType = ReferenceType; + a.referenceType = dict->var; + addPendingReference(dict->var); + return a; + } + } + + return (Variable_t) { 0 }; +} \ No newline at end of file diff --git a/source/script/dictionaryClass.h b/source/script/dictionaryClass.h index 665b57c..8cb5361 100644 --- a/source/script/dictionaryClass.h +++ b/source/script/dictionaryClass.h @@ -1,3 +1,6 @@ #pragma once #include "model.h" #include "genericClass.h" +#include "compat.h" + +Variable_t getDictMember(Variable_t* var, char* memberName); \ No newline at end of file diff --git a/source/script/eval.c b/source/script/eval.c index 41a6f46..7de4649 100644 --- a/source/script/eval.c +++ b/source/script/eval.c @@ -187,6 +187,9 @@ void runtimeVariableEdit(Callback_SetVar_t* set, Variable_t* curRes) { callMemberFunctionDirect(set->setVar, "set", args, 2); } + removePendingReference(curRes); + removePendingReference(set->setVar); + // TODO: add non-top level sets } diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 56f082e..7b9b412 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -13,6 +13,7 @@ #include "saveClass.h" #include "unsolvedArrayClass.h" #include "else.h" +#include "dictionaryClass.h" Variable_t* copyVariableToPtr(Variable_t var) { Variable_t* a = malloc(sizeof(Variable_t)); @@ -31,12 +32,12 @@ MemberGetters_t memberGetters[] = { {SolvedArrayReferenceClass, getArrayReferenceMember}, {UnresolvedArrayClass, getUnsolvedArrayMember}, {ElseClass, getElseMember}, + {DictionaryClass, getDictMember}, #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++) { @@ -45,6 +46,10 @@ Variable_t* genericGet(Variable_t* var, CallArgs_t* ref) { if (member.variableType == None) return NULL; + if (member.variableType == ReferenceType) { + return member.referenceType; + } + addPendingReference(var); // So caller doesn't fall out of scope. Don't forget to free! return copyVariableToPtr(member); } @@ -186,6 +191,7 @@ Variable_t* genericCall(Variable_t* var, CallArgs_t* ref) { } } +// TODO: add staticStorage Variable_t getGenericFunctionMember(Variable_t* var, char* memberName, ClassFunctionTableEntry_t* entries, u8 len) { Variable_t newVar = {.readOnly = 1, .variableType = FunctionClass}; newVar.function.origin = var; @@ -213,7 +219,12 @@ Variable_t* callMemberFunction(Variable_t* var, char* memberName, CallArgs_t* ar if (funcRef.variableType == None) return NULL; - return genericCall(&funcRef, args); + Variable_t* ptr = &funcRef; + if (funcRef.variableType == ReferenceType) { + ptr = funcRef.referenceType; + } + + return genericCall(ptr, args); } } @@ -228,7 +239,12 @@ Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable SCRIPT_FATAL_ERR("Did not find member '%s'", memberName); } - return genericCallDirect(&funcRef, args, argsLen); + Variable_t* ptr = &funcRef; + if (funcRef.variableType == ReferenceType) { + ptr = funcRef.referenceType; + } + + return genericCallDirect(ptr, args, argsLen); } } @@ -251,6 +267,13 @@ void freeVariableInternal(Variable_t* referencedTarget) { case IntArrayClass: vecFree(referencedTarget->solvedArray.vector); break; + case DictionaryClass:; + vecForEach(Dict_t*, dict, (&referencedTarget->dictionary.vector)) { + modReference(dict->var, 0); + free(dict->name); + } + FREE(referencedTarget->dictionary.vector.data); + break; } } diff --git a/source/script/model.h b/source/script/model.h index db004aa..d2596d1 100644 --- a/source/script/model.h +++ b/source/script/model.h @@ -36,6 +36,7 @@ typedef enum { SolvedArrayReferenceClass, SaveClass, ElseClass, + ReferenceType, } VariableType_t; typedef enum { @@ -176,6 +177,7 @@ typedef struct _Variable_t { #ifndef WIN32 SaveClass_t *save; #endif + struct _Variable_t* referenceType; }; union { struct { diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 084f57d..56d3818 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -79,6 +79,13 @@ ClassFunction(stdBreak) { return NULL; } +ClassFunction(stdDict) { + Variable_t a = { 0 }; + a.variableType = DictionaryClass; + a.dictionary.vector = newVec(sizeof(Dict_t), 0); + return copyVariableToPtr(a); +} + #ifndef WIN32 ClassFunction(stdMountSysmmc){ if (connectMMC(MMC_CONN_EMMC)) @@ -121,6 +128,7 @@ enum standardFunctionIndexes { STD_MOUNTSAVE, STD_EXIT, STD_BREAK, + STD_DICT, }; u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -135,6 +143,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { [STD_MOUNTSAVE] = {"readsave", stdMountSave, 1, oneStringArgStd}, [STD_EXIT] = {"exit", stdExit, 0, 0}, [STD_BREAK] = {"break", stdBreak, 0, 0}, + [STD_DICT] = {"dict", stdDict, 0, 0}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { From 3c640e23b1833a7f2255331416662497bbf8ebc4 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 13 Jul 2021 15:53:49 +0200 Subject: [PATCH 07/62] add string array indexing --- source/script/StringClass.c | 15 +++++++++++++++ source/script/genericClass.c | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/source/script/StringClass.c b/source/script/StringClass.c index c534d46..40e1903 100644 --- a/source/script/StringClass.c +++ b/source/script/StringClass.c @@ -1,6 +1,7 @@ #include "StringClass.h" #include "compat.h" #include "intClass.h" +#include "scriptError.h" #include char* getStringValue(Variable_t* var) { @@ -57,6 +58,19 @@ ClassFunction(stringBytes) { return copyVariableToPtr(v); } +ClassFunction(stringIndexGet) { + u32 len = strlen(caller->string.value); + u32 idx = args[0]->integer.value; + if (len < idx || idx < 0) { + SCRIPT_FATAL_ERR("Index of string out of range"); + } + + char* a = calloc(1,2); + a[0] = caller->string.value[idx]; + return newStringVariablePtr(a, 0, 0); +} + +u8 strOneIntArg[] = { IntClass }; u8 oneStringArg[] = { StringClass }; ClassFunctionTableEntry_t stringFunctions[] = { @@ -64,6 +78,7 @@ ClassFunctionTableEntry_t stringFunctions[] = { {"+", addStringVariables, 1, oneStringArg }, {"len", getStringLength, 0, 0}, {"bytes", stringBytes, 0, 0}, + {"get", stringIndexGet, 1, strOneIntArg}, }; Variable_t getStringMember(Variable_t* var, char* memberName) { diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 7b9b412..695961c 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -208,7 +208,6 @@ Variable_t getGenericFunctionMember(Variable_t* var, char* memberName, ClassFunc } } - printScriptError(SCRIPT_FATAL, "Could not find member of class"); return (Variable_t){ 0 }; } @@ -216,8 +215,9 @@ Variable_t* callMemberFunction(Variable_t* var, char* memberName, CallArgs_t* ar 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; + if (funcRef.variableType == None) { + SCRIPT_FATAL_ERR("Did not find member '%s'", memberName); + } Variable_t* ptr = &funcRef; if (funcRef.variableType == ReferenceType) { From 00fc3347640d41fa348221e15e70627746f66743 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 13 Jul 2021 16:30:34 +0200 Subject: [PATCH 08/62] implement the most important function --- source/script/standardLibrary.c | 11 +++++++++++ source/script/vector.c | 3 --- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 56d3818..f8d7672 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -111,6 +111,11 @@ ClassFunction(stdMountSave){ var.save = save; return copyVariableToPtr(var); } +ClassFunction(stdSetPixel) { + u32 color = getIntValue(args[2]); + gfx_set_pixel_horz(args[0]->integer.value, args[1]->integer.value, color); + return &emptyClass; +} #else ClassFunction(stdMountSysmmc){ return newIntVariablePtr(0); @@ -118,6 +123,9 @@ ClassFunction(stdMountSysmmc){ ClassFunction(stdMountSave){ return newIntVariablePtr(0); } +ClassFunction(stdSetPixel) { + return newIntVariablePtr(0); +} #endif enum standardFunctionIndexes { @@ -129,11 +137,13 @@ enum standardFunctionIndexes { STD_EXIT, STD_BREAK, STD_DICT, + STD_SETPIXEL, }; u8 oneIntoneFunction[] = { IntClass, FunctionClass }; u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; u8 oneStringArgStd[] = {StringClass}; +u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; ClassFunctionTableEntry_t standardFunctionDefenitions[] = { [STD_IF] = {"if", stdIf, 2, oneIntoneFunction}, @@ -144,6 +154,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { [STD_EXIT] = {"exit", stdExit, 0, 0}, [STD_BREAK] = {"break", stdBreak, 0, 0}, [STD_DICT] = {"dict", stdDict, 0, 0}, + [STD_SETPIXEL] = {"setpixel", stdSetPixel, 3, threeIntsStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { diff --git a/source/script/vector.c b/source/script/vector.c index b1a09ab..01e833e 100644 --- a/source/script/vector.c +++ b/source/script/vector.c @@ -50,9 +50,6 @@ int vecAddElem(Vector_t* v, void* elem, u8 sz) { 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) From b06085915de18a5cff7682812edf71436f3cc17a Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 17 Jul 2021 23:26:37 +0200 Subject: [PATCH 09/62] frii memory leak fix --- source/fs/menus/explorer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/fs/menus/explorer.c b/source/fs/menus/explorer.c index efe4631..f06679f 100644 --- a/source/fs/menus/explorer.c +++ b/source/fs/menus/explorer.c @@ -74,6 +74,7 @@ void FileExplorer(char *path){ res = 0; res = newMenu(&entries, res, 60, 42, ENABLEB | ENABLEPAGECOUNT, (int)fileVec.count); + vecFree(entries); char *oldPath = storedPath; @@ -125,6 +126,7 @@ void FileExplorer(char *path){ else if (res < ARR_LEN(topEntries)) { if (!strcmp(storedPath, path)){ clearFileVector(&fileVec); + free(storedPath); return; } From 3cd78d6efd5b288702d69b2f55be9288c947666f Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 18 Jul 2021 23:51:27 +0200 Subject: [PATCH 10/62] add scripts to the main menu, fix script parser reading beyond EOF --- source/fs/menus/explorer.h | 5 ++- source/fs/menus/filemenu.c | 2 +- source/script/ABadIdeaVersion3.c | 2 +- source/script/parser.c | 9 +++-- source/script/parser.h | 4 +- source/script/standardLibrary.c | 37 ++++++++--------- source/tegraexplorer/mainmenu.c | 68 ++++++++++++++++++++++++++++++-- 7 files changed, 94 insertions(+), 33 deletions(-) diff --git a/source/fs/menus/explorer.h b/source/fs/menus/explorer.h index 840f4d8..cda9e09 100644 --- a/source/fs/menus/explorer.h +++ b/source/fs/menus/explorer.h @@ -1,4 +1,7 @@ #pragma once #include "../../utils/vector.h" +#include "../../gfx/menu.h" +#include "../fstypes.h" -void FileExplorer(char *path); \ No newline at end of file +void FileExplorer(char *path); +MenuEntry_t MakeMenuOutFSEntry(FSEntry_t entry); \ No newline at end of file diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index dc9caca..0beff1a 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -101,7 +101,7 @@ void RunScript(char *path, FSEntry_t entry){ gfx_printf("Init gc\n"); initGarbageCollector(); gfx_printf("Parsing\n"); - ParserRet_t ret = parseScript(script); + ParserRet_t ret = parseScript(script, size); free(script); gfx_printf("Init vars\n"); setStaticVars(&ret.staticVarHolder); diff --git a/source/script/ABadIdeaVersion3.c b/source/script/ABadIdeaVersion3.c index 5a52ce9..5e0a4e0 100644 --- a/source/script/ABadIdeaVersion3.c +++ b/source/script/ABadIdeaVersion3.c @@ -71,7 +71,7 @@ int main() //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); + ParserRet_t ret = parseScript(script, strlen(script)); free(script); setStaticVars(&ret.staticVarHolder); diff --git a/source/script/parser.c b/source/script/parser.c index 359c996..0833042 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -71,6 +71,8 @@ typedef enum { History_Array, } StackHistory_t; +char* end; + u8 nextToken(char** inPtr, void** val) { char* in = *inPtr; u8 ret = Token_Err; @@ -191,7 +193,7 @@ u8 nextToken(char** inPtr, void** val) { ret = Token_String; *val = storage; } - else if (*in == '\0') { + else if (*in == '\0' || in > end) { *inPtr = in; return ret; } @@ -258,7 +260,7 @@ int isLastVarCall(Operator_t* opHolder) { return (opHolder->token == CallArgs && getLastRef(&opHolder->callArgs)->action == ActionCall); } -ParserRet_t parseScript(char* in) { +ParserRet_t parseScript(char* in, u32 len) { Vector_t functionStack; // Function_t Vector_t stackHistoryHolder; // StaticHistory_t Vector_t staticVariableHolder; // Variable_t @@ -275,8 +277,9 @@ ParserRet_t parseScript(char* in) { u8 notNext = 0; lineNumber = 1; scriptCurrentLine = 1; + end = in + len; - while (*in) { + while (*in && in <= end) { Function_t* lastFunc = getStackEntry(&functionStack); StackHistory_t* lastHistory = getStackEntry(&stackHistoryHolder); diff --git a/source/script/parser.h b/source/script/parser.h index b09bd7a..c81e3a2 100644 --- a/source/script/parser.h +++ b/source/script/parser.h @@ -10,6 +10,6 @@ typedef struct { #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 +void exitFunction(Operator_t* start, u32 len); +ParserRet_t parseScript(char* in, u32 len); \ No newline at end of file diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index f8d7672..cf7719e 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -70,6 +70,12 @@ ClassFunction(stdPrint) { return &emptyClass; } +ClassFunction(stdPrintLn) { + stdPrint(caller, args, argsLen); + gfx_printf("\n"); + return &emptyClass; +} + ClassFunction(stdExit) { return NULL; } @@ -128,33 +134,22 @@ ClassFunction(stdSetPixel) { } #endif -enum standardFunctionIndexes { - STD_IF = 0, - STD_WHILE, - STD_PRINT, - STD_MOUNTSYSMMC, - STD_MOUNTSAVE, - STD_EXIT, - STD_BREAK, - STD_DICT, - STD_SETPIXEL, -}; - u8 oneIntoneFunction[] = { IntClass, FunctionClass }; u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; u8 oneStringArgStd[] = {StringClass}; u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; 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}, - [STD_BREAK] = {"break", stdBreak, 0, 0}, - [STD_DICT] = {"dict", stdDict, 0, 0}, - [STD_SETPIXEL] = {"setpixel", stdSetPixel, 3, threeIntsStd}, + {"if", stdIf, 2, oneIntoneFunction}, + {"while", stdWhile, 2, doubleFunctionClass}, + {"print", stdPrint, VARARGCOUNT, 0}, + {"println", stdPrintLn, VARARGCOUNT, 0}, + {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, + {"readsave", stdMountSave, 1, oneStringArgStd}, + {"exit", stdExit, 0, 0}, + {"break", stdBreak, 0, 0}, + {"dict", stdDict, 0, 0}, + {"setpixel", stdSetPixel, 3, threeIntsStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index feffed2..48c2112 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -17,6 +17,10 @@ #include #include "../utils/utils.h" #include "../config.h" +#include "../fs/readers/folderReader.h" +#include +#include +#include "../fs/menus/filemenu.h" extern hekate_config h_cfg; @@ -36,7 +40,8 @@ enum { MainRebootRCM, MainRebootNormal, MainRebootHekate, - MainRebootAMS + MainRebootAMS, + MainScripts, }; MenuEntry_t mainMenuEntries[] = { @@ -55,7 +60,8 @@ MenuEntry_t mainMenuEntries[] = { [MainRebootRCM] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to RCM"}, [MainRebootNormal] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot normally"}, [MainRebootHekate] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to bootloader/update.bin"}, - [MainRebootAMS] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to atmosphere/reboot_payload.bin"} + [MainRebootAMS] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to atmosphere/reboot_payload.bin"}, + [MainScripts] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "\n-- Scripts --"} }; void HandleSD(){ @@ -108,6 +114,13 @@ void ViewCredits(){ if (hidRead()->r) gfx_printf("%k\"I'm not even sure if it works\" - meme", COLOR_ORANGE); + +/* Leaving this here for my debugging needs :) + heap_monitor_t a = {0}; + heap_monitor(&a, false); + gfx_printf("\nUsed: %d\nTotal: %d\n", a.used, a.total); +*/ + hidWait(); } @@ -168,13 +181,60 @@ void EnterMainMenu(){ mainMenuEntries[MainRebootHekate].hide = (!sd_mounted || !FileExists("sd:/bootloader/update.bin")); mainMenuEntries[MainRebootRCM].hide = h_cfg.t210b01; + // -- Scripts -- + mainMenuEntries[MainScripts].hide = (!sd_mounted || !FileExists("sd:/tegraexplorer/scripts")); + + Vector_t ent = vecFromArray(mainMenuEntries, ARR_LEN(mainMenuEntries), sizeof(MenuEntry_t)); + Vector_t scriptFiles = {0}; + u8 hasScripts = 0; + + if (!mainMenuEntries[MainScripts].hide){ + int res = 0; + scriptFiles = ReadFolder("sd:/tegraexplorer/scripts", &res); + if (!res){ + if (!scriptFiles.count){ + free(scriptFiles.data); + mainMenuEntries[MainScripts].hide = 1; + } + else { + hasScripts = 1; + ent = newVec(sizeof(MenuEntry_t), ARRAY_SIZE(mainMenuEntries) + scriptFiles.count); + ent.count = ARRAY_SIZE(mainMenuEntries); + memcpy(ent.data, mainMenuEntries, sizeof(MenuEntry_t) * ARRAY_SIZE(mainMenuEntries)); + vecForEach(FSEntry_t*, scriptFile, (&scriptFiles)){ + if (!scriptFile->isDir && StrEndsWith(scriptFile->name, ".te")){ + MenuEntry_t a = MakeMenuOutFSEntry(*scriptFile); + vecAdd(&ent, a); + } + } + + if (ent.count == ARRAY_SIZE(mainMenuEntries)){ + clearFileVector(&scriptFiles); + free(ent.data); + ent = vecFromArray(mainMenuEntries, ARR_LEN(mainMenuEntries), sizeof(MenuEntry_t)); + hasScripts = 0; + mainMenuEntries[MainScripts].hide = 1; + } + } + } + } + gfx_clearscreen(); gfx_putc('\n'); - Vector_t ent = vecFromArray(mainMenuEntries, ARR_LEN(mainMenuEntries), sizeof(MenuEntry_t)); res = newMenu(&ent, res, 79, 30, ALWAYSREDRAW, 0); - if (mainMenuPaths[res] != NULL) + if (res < MainScripts && mainMenuPaths[res] != NULL) mainMenuPaths[res](); + else if (hasScripts){ + vecDefArray(FSEntry_t*, scriptFilesArray, scriptFiles); + RunScript("sd:/tegraexplorer/scripts", scriptFilesArray[res - ARRAY_SIZE(mainMenuEntries)]); + hidWait(); + } + + if (hasScripts){ + clearFileVector(&scriptFiles); + free(ent.data); + } } } From 2311c52ebf6c6dc8269c40a2cdba583520dd987b Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 19 Jul 2021 12:28:40 +0200 Subject: [PATCH 11/62] remove old gc code --- source/fs/menus/filemenu.c | 3 - source/script/ABadIdeaVersion3.c | 3 - source/script/garbageCollector.c | 116 +------------------------------ source/script/garbageCollector.h | 4 -- 4 files changed, 1 insertion(+), 125 deletions(-) diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 0beff1a..34aba6b 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -98,8 +98,6 @@ void RunScript(char *path, FSEntry_t entry){ lexarVectorClear(&ctx.script); */ - gfx_printf("Init gc\n"); - initGarbageCollector(); gfx_printf("Parsing\n"); ParserRet_t ret = parseScript(script, size); free(script); @@ -111,7 +109,6 @@ void RunScript(char *path, FSEntry_t entry){ 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); diff --git a/source/script/ABadIdeaVersion3.c b/source/script/ABadIdeaVersion3.c index 5e0a4e0..5da3b17 100644 --- a/source/script/ABadIdeaVersion3.c +++ b/source/script/ABadIdeaVersion3.c @@ -62,8 +62,6 @@ int main() return; */ - - initGarbageCollector(); char* script = readFile("input.te"); if (script == NULL) @@ -80,7 +78,6 @@ int main() 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); diff --git a/source/script/garbageCollector.c b/source/script/garbageCollector.c index 0eaca3b..11bd98e 100644 --- a/source/script/garbageCollector.c +++ b/source/script/garbageCollector.c @@ -3,23 +3,6 @@ #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; @@ -30,6 +13,7 @@ void modReference(Variable_t* ref, u8 add) { else { ref->tagCount--; if (ref->tagCount <= 0) { + // TODO: move to parser.c if (ref->variableType == FunctionClass && ref->function.builtIn && ref->function.origin != NULL) modReference(ref->function.origin, 0); @@ -39,102 +23,4 @@ void modReference(Variable_t* ref, u8 add) { freeVariable(&ref); } } - - /* - 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 index e014ebe..f60a706 100644 --- a/source/script/garbageCollector.h +++ b/source/script/garbageCollector.h @@ -1,9 +1,5 @@ #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); From e49f184f9b60c490bec2b27083756c61a51b0968 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 19 Jul 2021 16:25:32 +0200 Subject: [PATCH 12/62] properly implement #REQUIRE (VER x.x.x, MINERVA, KEYS) --- Makefile | 3 +- source/script/compat.h | 1 + source/script/parser.c | 50 ++++++++++++++++++++------------- source/script/scriptError.h | 1 + source/tegraexplorer/mainmenu.c | 8 ++++-- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index f88173a..c9b3049 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ IPL_LOAD_ADDR := 0x40008000 LPVERSION_MAJOR := 3 LPVERSION_MINOR := 0 LPVERSION_BUGFX := 6 +LPVERSION := \"$(LPVERSION_MAJOR).$(LPVERSION_MINOR).$(LPVERSION_BUGFX)\" ################################################################################ @@ -40,7 +41,7 @@ FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"' ################################################################################ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) +CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -DLP_VER=$(LPVERSION) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) # 0: UART_A, 1: UART_B. diff --git a/source/script/compat.h b/source/script/compat.h index 63eebf3..0c594c5 100644 --- a/source/script/compat.h +++ b/source/script/compat.h @@ -9,6 +9,7 @@ #define LP_VER_MJ 3 #define LP_VER_MN 0 #define LP_VER_BF 5 + #define LP_VER "3.0.5" #define FREE(x) if (x) free(x) #define CpyStr(x) _strdup(x); #include "vector.h" diff --git a/source/script/parser.c b/source/script/parser.c index 0833042..100a73e 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -13,6 +13,10 @@ #include "scriptError.h" #include "standardLibrary.h" +#ifndef WIN32 +#include "../tegraexplorer/tconf.h" +#endif + static inline int isValidWord(char c) { char r = c | 0x20; return ((r >= 'a' && r <= 'z') || c == '_'); @@ -80,36 +84,42 @@ u8 nextToken(char** inPtr, void** val) { 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++; - } + char* verEnd = 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; - } + while (isValidNum(*verEnd) || *verEnd == '.') + verEnd++; + + u8 outdated = (verEnd - verStart != strlen(LP_VER)); + + if (!outdated){ + outdated = (memcmp(LP_VER, verStart, verEnd - verStart) < 0); } if (outdated) { - printScriptError(SCRIPT_FATAL, "Script requires TegraExplorer %d.%d.%d or up!", vers[0], vers[1], vers[2]); + printScriptError(SCRIPT_LEXER_FATAL, "Script requires a newer TegraExplorer version!"); return Token_Fatal_Err; } } else if (!memcmp(in + 9, "MINERVA", 7)) { - u8 minervaEnabled = 0; // TODO: Change this to the actual value + #ifdef WIN32 + u8 minervaEnabled = 0; + #else + u8 minervaEnabled = TConf.minervaEnabled; + #endif if (!minervaEnabled) { - printScriptError(SCRIPT_FATAL, "Extended memory required.\nPut the bootloader folder from hekate on your sd!"); + printScriptError(SCRIPT_LEXER_FATAL, "Extended memory required.\nPut the bootloader folder from hekate on your sd!"); + return Token_Fatal_Err; + } + } + else if (!memcmp(in + 9, "KEYS", 4)) { + #ifdef WIN32 + u8 gotKeys = 0; + #else + u8 gotKeys = TConf.keysDumped; + #endif + if (!gotKeys){ + printScriptError(SCRIPT_LEXER_FATAL, "Keys required.\nMake sure you're on the latest version of TegraExplorer!"); return Token_Fatal_Err; } } diff --git a/source/script/scriptError.h b/source/script/scriptError.h index 161c55f..8b4d74f 100644 --- a/source/script/scriptError.h +++ b/source/script/scriptError.h @@ -5,6 +5,7 @@ enum { SCRIPT_FATAL = 0, SCRIPT_PARSER_FATAL, SCRIPT_WARN, + SCRIPT_LEXER_FATAL, SCRIPT_BREAK, }; diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 48c2112..714593e 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -222,12 +222,14 @@ void EnterMainMenu(){ gfx_clearscreen(); gfx_putc('\n'); - res = newMenu(&ent, res, 79, 30, ALWAYSREDRAW, 0); + res = newMenu(&ent, res, 79, 30, (ent.count == ARRAY_SIZE(mainMenuEntries)) ? ALWAYSREDRAW : ALWAYSREDRAW | ENABLEPAGECOUNT, ent.count - ARRAY_SIZE(mainMenuEntries)); if (res < MainScripts && mainMenuPaths[res] != NULL) mainMenuPaths[res](); else if (hasScripts){ - vecDefArray(FSEntry_t*, scriptFilesArray, scriptFiles); - RunScript("sd:/tegraexplorer/scripts", scriptFilesArray[res - ARRAY_SIZE(mainMenuEntries)]); + vecDefArray(MenuEntry_t*, entArray, ent); + MenuEntry_t entry = entArray[res]; + FSEntry_t fsEntry = {.name = entry.name, .sizeUnion = entry.sizeUnion}; + RunScript("sd:/tegraexplorer/scripts", fsEntry); hidWait(); } From 27350c0a5fdbb8ec55332c62c698ebd50e6a1f84 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 19 Jul 2021 21:44:15 +0200 Subject: [PATCH 13/62] add embedding TE scripts --- .gitignore | 4 ++ scripts/HelloWorld.te | 12 ++++++ source/fs/menus/filemenu.c | 17 +++++++++ source/fs/menus/filemenu.h | 3 +- source/tegraexplorer/mainmenu.c | 55 +++++++++++++++++++-------- te2c.py | 67 +++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 scripts/HelloWorld.te create mode 100644 te2c.py diff --git a/.gitignore b/.gitignore index 41dc2e1..8b35bd1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ source/script/*.te source/script/.vs *.exe + +source/script/builtin.c + +source/script/builtin.h diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te new file mode 100644 index 0000000..280d909 --- /dev/null +++ b/scripts/HelloWorld.te @@ -0,0 +1,12 @@ +#REQUIRE VER 3.0.6 +#REQUIRE MINERVA +#REQUIRE KEYS + +a="Hello world!\n" +a.print() + +i=0 +while (i<10){ + println(i) + i=i+1 +} \ No newline at end of file diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 34aba6b..43ae601 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -72,6 +72,23 @@ void DeleteFile(char *path, FSEntry_t entry){ free(thing); } +void RunScriptString(char *str, u32 size){ + gfx_clearscreen(); + ParserRet_t ret = parseScript(str, size); + setStaticVars(&ret.staticVarHolder); + initRuntimeVars(); + Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); + + exitRuntimeVars(); + exitStaticVars(&ret.staticVarHolder); + exitFunction(ret.main.operations.data, ret.main.operations.count); + vecFree(ret.staticVarHolder); + vecFree(ret.main.operations); + + hidWait(); + hidWait(); +} + void RunScript(char *path, FSEntry_t entry){ char *thing = CombinePaths(path, entry.name); u32 size; diff --git a/source/fs/menus/filemenu.h b/source/fs/menus/filemenu.h index debcedd..0699e25 100644 --- a/source/fs/menus/filemenu.h +++ b/source/fs/menus/filemenu.h @@ -4,4 +4,5 @@ typedef void (*fileMenuPath)(char *path, FSEntry_t entry); void FileMenu(char *path, FSEntry_t entry); -void RunScript(char *path, FSEntry_t entry); \ No newline at end of file +void RunScript(char *path, FSEntry_t entry); +void RunScriptString(char *str, u32 size); \ No newline at end of file diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 714593e..16fccf5 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -22,6 +22,12 @@ #include #include "../fs/menus/filemenu.h" +//#define INCLUDE_BUILTIN_SCRIPTS 1 + +#ifdef INCLUDE_BUILTIN_SCRIPTS +#include "../script/builtin.h" +#endif + extern hekate_config h_cfg; enum { @@ -182,25 +188,34 @@ void EnterMainMenu(){ mainMenuEntries[MainRebootRCM].hide = h_cfg.t210b01; // -- Scripts -- + #ifndef INCLUDE_BUILTIN_SCRIPTS mainMenuEntries[MainScripts].hide = (!sd_mounted || !FileExists("sd:/tegraexplorer/scripts")); + #else + mainMenuEntries[MainScripts].hide = ((!sd_mounted || !FileExists("sd:/tegraexplorer/scripts")) && !EMBEDDED_SCRIPTS_LEN); + #endif - Vector_t ent = vecFromArray(mainMenuEntries, ARR_LEN(mainMenuEntries), sizeof(MenuEntry_t)); + Vector_t ent = newVec(sizeof(MenuEntry_t), ARRAY_SIZE(mainMenuEntries)); + ent.count = ARRAY_SIZE(mainMenuEntries); + memcpy(ent.data, mainMenuEntries, sizeof(MenuEntry_t) * ARRAY_SIZE(mainMenuEntries)); Vector_t scriptFiles = {0}; u8 hasScripts = 0; - if (!mainMenuEntries[MainScripts].hide){ - int res = 0; + #ifdef INCLUDE_BUILTIN_SCRIPTS + for (int i = 0; i < EMBEDDED_SCRIPTS_LEN; i++){ + MenuEntry_t m = {.name = embedded_scripts_g[i].name, .optionUnion = COLORTORGB(COLOR_BLUE), .icon = 128}; + vecAdd(&ent, m); + } + #endif + + if (sd_mounted && FileExists("sd:/tegraexplorer/scripts")){ scriptFiles = ReadFolder("sd:/tegraexplorer/scripts", &res); if (!res){ if (!scriptFiles.count){ - free(scriptFiles.data); + FREE(scriptFiles.data); mainMenuEntries[MainScripts].hide = 1; } else { hasScripts = 1; - ent = newVec(sizeof(MenuEntry_t), ARRAY_SIZE(mainMenuEntries) + scriptFiles.count); - ent.count = ARRAY_SIZE(mainMenuEntries); - memcpy(ent.data, mainMenuEntries, sizeof(MenuEntry_t) * ARRAY_SIZE(mainMenuEntries)); vecForEach(FSEntry_t*, scriptFile, (&scriptFiles)){ if (!scriptFile->isDir && StrEndsWith(scriptFile->name, ".te")){ MenuEntry_t a = MakeMenuOutFSEntry(*scriptFile); @@ -210,14 +225,13 @@ void EnterMainMenu(){ if (ent.count == ARRAY_SIZE(mainMenuEntries)){ clearFileVector(&scriptFiles); - free(ent.data); - ent = vecFromArray(mainMenuEntries, ARR_LEN(mainMenuEntries), sizeof(MenuEntry_t)); hasScripts = 0; mainMenuEntries[MainScripts].hide = 1; } } } } + gfx_clearscreen(); gfx_putc('\n'); @@ -226,17 +240,28 @@ void EnterMainMenu(){ if (res < MainScripts && mainMenuPaths[res] != NULL) mainMenuPaths[res](); else if (hasScripts){ - vecDefArray(MenuEntry_t*, entArray, ent); - MenuEntry_t entry = entArray[res]; - FSEntry_t fsEntry = {.name = entry.name, .sizeUnion = entry.sizeUnion}; - RunScript("sd:/tegraexplorer/scripts", fsEntry); - hidWait(); + #ifdef INCLUDE_BUILTIN_SCRIPTS + if (res - ARRAY_SIZE(mainMenuEntries) < EMBEDDED_SCRIPTS_LEN){ + char *script = embedded_scripts_g[res - ARRAY_SIZE(mainMenuEntries)].script; + RunScriptString(script, strlen(script)); + } + else { + #endif + vecDefArray(MenuEntry_t*, entArray, ent); + MenuEntry_t entry = entArray[res]; + FSEntry_t fsEntry = {.name = entry.name, .sizeUnion = entry.sizeUnion}; + RunScript("sd:/tegraexplorer/scripts", fsEntry); + hidWait(); + #ifdef INCLUDE_BUILTIN_SCRIPTS + } + #endif } if (hasScripts){ clearFileVector(&scriptFiles); - free(ent.data); } + + free(ent.data); } } diff --git a/te2c.py b/te2c.py new file mode 100644 index 0000000..cf30915 --- /dev/null +++ b/te2c.py @@ -0,0 +1,67 @@ +""" +Usage: python te2c.py dest src_folder +Usage for TE: py te2c.py source/script/builtin scripts +Creator: https://github.com/maddiethecafebabe +""" + +import os +import sys +import string +from typing import List, Tuple, Dict + +IDENTCHARS = string.ascii_letters + string.digits + +SOURCE_HEADER = """ /* this file has been autogenerated with te2c.py */ +#include "{}"\n +""" + +HEADER_DEF = """ /* this file has been autogenerated with te2c.py */ +#ifndef TE_EMBEDDED_SCRIPTS_H +#define TE_EMBEDDED_SCRIPTS_H + +typedef struct {{ + const char const * script; + const char const * name; +}} embedded_script_t; + +extern const embedded_script_t embedded_scripts_g[]; + +#define EMBEDDED_SCRIPTS_LEN {} + +#endif /* TE_EMBEDDED_SCRIPTS_H */ +""" + +def gather_scripts(path: str, suffix: str=".te") -> List[Tuple[str, str]]: + files = [] + for dirname, _, filenames in os.walk(path): + files += [(f, os.path.join(dirname, f)) for f in filenames if f.endswith(suffix)] + return files + +def process_script(path: str) -> str: + with open(path, "r") as fp: + raw = fp.readlines() + return str().join(line.__repr__()[1:-1].replace("\"", "\\\"").replace("\\t", "") for line in raw) + +def process_name(name: str) -> str: + return "script_" + str().join(c for c in name.split(".")[0] if c in IDENTCHARS) + "_g" + +def map_scripts_from(path: str, suffix: str=".te") -> Dict[str, Dict[str, str]]: + return {process_name(name): {"script": process_script(path), "og-name": name} for (name, path) in gather_scripts(path, suffix=suffix)} + +def te2c(dest: str, path: str, suffix: str=".te"): + script_map = map_scripts_from(path, suffix=suffix) + with open(dest + ".c", "w") as fp: + fp.write(SOURCE_HEADER.format(os.path.basename(dest) + ".h")) + fp.write( + "const embedded_script_t embedded_scripts_g[] = {{\n{}}};\n".format( + str().join( + f"\t{{ .name = \"{vals['og-name']}\", .script = \"{vals['script']}\"}}, \n" for name, vals in script_map.items() + ) + ) + ) + + with open(dest + ".h", "w") as fp: + fp.write(HEADER_DEF.format(len(script_map))) + +if __name__ == "__main__": + te2c(dest=sys.argv[1], path=sys.argv[2]) From d7ebd9fdbe34131f05c7ad5810f7ea9f97630bc0 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Wed, 21 Jul 2021 01:30:08 +0200 Subject: [PATCH 14/62] safety push --- Makefile | 3 +++ source/script/StringClass.c | 11 +++++++++++ source/script/arrayClass.c | 21 +++++++++++++++++++++ source/script/genericClass.c | 9 ++++++++- te2c.py | 1 + 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c9b3049..670b9f0 100644 --- a/Makefile +++ b/Makefile @@ -104,3 +104,6 @@ $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S @mkdir -p "$(@D)" $(CC) $(CFLAGS) -c $< -o $@ + +$(SOURCEDIR)/script/builtin.c: scripts/*.te + @py te2c.py source/script/builtin scripts diff --git a/source/script/StringClass.c b/source/script/StringClass.c index 40e1903..c5cf5df 100644 --- a/source/script/StringClass.c +++ b/source/script/StringClass.c @@ -70,6 +70,16 @@ ClassFunction(stringIndexGet) { return newStringVariablePtr(a, 0, 0); } +ClassFunction(stringMinusInt){ + u32 baseStrLen = strlen(caller->string.value); + if (baseStrLen < args[0]->integer.value){ + SCRIPT_FATAL_ERR("Index of string out of range"); + } + char* newStr = calloc(baseStrLen - args[0]->integer.value + 1, 1); + memcpy(newStr, caller->string.value, baseStrLen - args[0]->integer.value); + return newStringVariablePtr(newStr, 0, 1); +} + u8 strOneIntArg[] = { IntClass }; u8 oneStringArg[] = { StringClass }; @@ -79,6 +89,7 @@ ClassFunctionTableEntry_t stringFunctions[] = { {"len", getStringLength, 0, 0}, {"bytes", stringBytes, 0, 0}, {"get", stringIndexGet, 1, strOneIntArg}, + {"-", stringMinusInt, 1, strOneIntArg}, }; Variable_t getStringMember(Variable_t* var, char* memberName) { diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index 4a37057..4fbb9cf 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -226,6 +226,25 @@ ClassFunction(eqArray){ return newIntVariablePtr(!res); } +ClassFunction(arrayFind){ + Variable_t *arg = (*args); + if (caller->solvedArray.vector.count <= arg->solvedArray.vector.count || arg->variableType != caller->variableType){ + return newIntVariablePtr(-1); + } + + u8 step = (arg->variableType == ByteArrayClass) ? 1 : 8; + char *haystack = caller->solvedArray.vector.data; + void *needle = arg->solvedArray.vector.data; + + for (int i = 0; i < caller->solvedArray.vector.count - arg->solvedArray.vector.count; i++){ + if (!memcmp(haystack + (i * step), needle, step * arg->solvedArray.vector.count)){ + return newIntVariablePtr(i); + } + } + + return newIntVariablePtr(-1); +} + ClassFunctionTableEntry_t arrayFunctions[] = { {"get", getArrayIdx, 1, anotherOneIntArg }, {"len", getArrayLen, 0, 0}, @@ -239,6 +258,8 @@ ClassFunctionTableEntry_t arrayFunctions[] = { {"bytestostr", bytesToStr, 0, 0}, {"==", eqArray, 1, oneByteArrayClass}, {"==", eqArray, 1, oneIntArrayClass}, + {"find", arrayFind, 1, oneByteArrayClass}, + {"find", arrayFind, 1, oneIntArrayClass}, }; Variable_t getArrayMember(Variable_t* var, char* memberName) { diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 695961c..4aa0597 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -274,7 +274,14 @@ void freeVariableInternal(Variable_t* referencedTarget) { } FREE(referencedTarget->dictionary.vector.data); break; - } + case SaveClass:; + #ifndef WIN32 + save_free_contexts(&referencedTarget->save->saveCtx); + f_close(&referencedTarget->save->saveFile); + FREE(referencedTarget->save); + #endif // !WIN32 + break; + } } void freeVariable(Variable_t** target) { diff --git a/te2c.py b/te2c.py index cf30915..892ef33 100644 --- a/te2c.py +++ b/te2c.py @@ -65,3 +65,4 @@ def te2c(dest: str, path: str, suffix: str=".te"): if __name__ == "__main__": te2c(dest=sys.argv[1], path=sys.argv[2]) + print("converting .te files done!") From 3ab95dfd64cc6b15d6c5359c06f5ff6a2078d7ba Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Wed, 21 Jul 2021 15:19:27 +0200 Subject: [PATCH 15/62] add crude firmware dumping script --- scripts/FirmwareDump.te | 77 +++++++++++++++++++++++++ scripts/HelloWorld.te | 20 +++++-- source/script/genericClass.c | 2 - source/script/intClass.c | 9 +++ source/script/standardLibrary.c | 99 +++++++++++++++++++++++++++++++++ source/tegraexplorer/mainmenu.c | 5 +- 6 files changed, 202 insertions(+), 10 deletions(-) create mode 100644 scripts/FirmwareDump.te diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te new file mode 100644 index 0000000..1a56086 --- /dev/null +++ b/scripts/FirmwareDump.te @@ -0,0 +1,77 @@ +if (mountsys("SYSTEM")){ + print("SYSTEM MOUNT FAIL") + exit() +} + +a = readsave("bis:/save/8000000000000120") +b = a.readFile("/meta/imkvdb.arc") +print(b.len(), "\n") + +c = ["BYTE[]", 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01] + +i = 1 +#while (i + c.len() < b.len()){ +# if (b.slice(i, 8).project() == c) {\ + +fuck = b.find(c) +if (fuck < 0) { + print("Not found") + exit() +} + +i = fuck + +d = b.slice(i + 8, 4).project() +ver = (d[3] << 24) | (d[2] << 16) | (d[1] << 8) | (d[0]) +rev = (ver & ((1 << 16) - 1)) +pat = ((ver >> 16) & ((1 << 4) - 1)) +min = ((ver >> 20) & ((1 << 6) - 1)) +maj = ((ver >> 26) & ((1 << 6) - 1)) +print("") +println(ver.str(), " ", maj.str(), ".", min.str(), ".", pat.str(), ".", rev.str()) + + +# i = i + 1 +#} + + +mkdir("sd:/tegraexplorer") +mkdir("sd:/tegraexplorer/Firmware") +baseSdPath = "sd:/tegraexplorer/Firmware/" + maj.str() + "." + min.str() + "." + pat.str() +mkdir(baseSdPath) + +contents = readdir("bis:/Contents/registered") +if (contents.result != 0){ + println("Fail reading dir") + exit() +} + +contents.files.foreach("x") { + fullPath = "bis:/Contents/registered/" + x + name = x + if (ncatype(fullPath) == 1){ + name = name - 4 + ".cnmt.nca" + } + print("\r", x) + fullSdPath = baseSdPath + "/" + name + if (filecopy(fullPath, fullSdPath)){ + println("\nErr during copy") + exit() + } +} + +contents.folders.foreach("x") { + fullPath = "bis:/Contents/registered/" + x + "/00" + name = x + if (ncatype(fullPath) == 1){ + name = name - 4 + ".cnmt.nca" + } + print("\r", x) + fullSdPath = baseSdPath + "/" + name + if (filecopy(fullPath, fullSdPath)){ + println("\nErr during copy") + exit() + } +} + +print("end") \ No newline at end of file diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te index 280d909..e373aaa 100644 --- a/scripts/HelloWorld.te +++ b/scripts/HelloWorld.te @@ -5,8 +5,18 @@ a="Hello world!\n" a.print() -i=0 -while (i<10){ - println(i) - i=i+1 -} \ No newline at end of file +#i=0 +#while (i<10){ +# println(i) +# i=i+1 +#} + +a = readdir("sd:/tegraexplorer") +println(a.result) +println(a.files.len()) +println(a.folders.len()) +println(a.fileSizes.len()) + +a.files.foreach("b") { + println(b) +} \ No newline at end of file diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 4aa0597..9dde959 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -255,8 +255,6 @@ Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable 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: diff --git a/source/script/intClass.c b/source/script/intClass.c index d03988e..065356b 100644 --- a/source/script/intClass.c +++ b/source/script/intClass.c @@ -1,7 +1,9 @@ #include "intClass.h" +#include "StringClass.h" #include "compat.h" #include #include +#include IntClass_t createIntClass(s64 in) { IntClass_t a = { in }; @@ -20,6 +22,12 @@ ClassFunction(printIntVariable) { return &emptyClass; } +ClassFunction(intToStr) { + char buff[64] = {0}; + s_printf(buff, "%d", getIntValue(caller)); + return newStringVariablePtr(CpyStr(buff), 0, 1); +} + #define IntOpFunction(name, op) ClassFunction(name) { s64 i1 = getIntValue(caller); s64 i2 = getIntValue(*args); return newIntVariablePtr((i1 op i2)); } IntOpFunction(addInt, +) @@ -52,6 +60,7 @@ u8 oneIntArgInt[] = { IntClass }; ClassFunctionTableEntry_t intFunctions[] = { {"print", printIntVariable, 0, 0}, {"not", notInt, 0, 0}, + {"str", intToStr, 0, 0}, IntOpFunctionEntry("+", addInt), IntOpFunctionEntry("-", minusInt), IntOpFunctionEntry("*", multInt), diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index cf7719e..6c26dd8 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -11,6 +11,10 @@ #ifndef WIN32 #include "../storage/mountmanager.h" #include "../keys/keys.h" +#include "../fs/readers/folderReader.h" +#include "../fs/fscopy.h" +#include +#include "../keys/nca.h" #endif ClassFunction(stdIf) { @@ -122,6 +126,79 @@ ClassFunction(stdSetPixel) { gfx_set_pixel_horz(args[0]->integer.value, args[1]->integer.value, color); return &emptyClass; } + +ClassFunction(stdReadDir){ + Vector_t dict = newVec(sizeof(Dict_t), 4); + Variable_t* resPtr = newIntVariablePtr(0); + Dict_t temp = {.name = CpyStr("result"), .var = resPtr}; + vecAdd(&dict, temp); + + Variable_t fileNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; + Variable_t dirNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; + Variable_t fileSizeArray = {.variableType = IntArrayClass, .solvedArray.vector = newVec(sizeof(s64), 0)}; + + DIR dir; + if ((resPtr->integer.value = f_opendir(&dir, args[0]->string.value))){ + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = dict}; + return copyVariableToPtr(ret); + } + + FILINFO fno; + while (!(resPtr->integer.value = f_readdir(&dir, &fno)) && fno.fname[0]){ + char *name = CpyStr(fno.fname); + if (fno.fattrib & AM_DIR){ + vecAdd(&dirNamesArray.solvedArray.vector, name); + } + else { + vecAdd(&fileNamesArray.solvedArray.vector, name); + s64 size = fno.fsize; + vecAdd(&fileSizeArray.solvedArray.vector, size); + } + } + + f_closedir(&dir); + + temp.name = CpyStr("files"); + temp.var = copyVariableToPtr(fileNamesArray); + vecAdd(&dict, temp); + + temp.name = CpyStr("folders"); + temp.var = copyVariableToPtr(dirNamesArray); + vecAdd(&dict, temp); + + temp.name = CpyStr("fileSizes"); + temp.var = copyVariableToPtr(fileSizeArray); + vecAdd(&dict, temp); + + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = dict}; + return copyVariableToPtr(ret); +} + +ClassFunction(stdFileCopy){ + ErrCode_t e = FileCopy(args[0]->string.value, args[1]->string.value, 0); + return newIntVariablePtr(e.err); +} + +ClassFunction(stdMkdir){ + return newIntVariablePtr(f_mkdir(args[0]->string.value)); +} + +// Broken???? +ClassFunction(stdGetMemUsage){ + heap_monitor_t mon; + heap_monitor(&mon, false); + Dict_t a = {.name = CpyStr("used"), .var = newIntVariablePtr((s64)mon.used)}; + Dict_t b = {.name = CpyStr("total"), .var = newIntVariablePtr((s64)mon.total)}; + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 2)}; + vecAdd(&ret, a); + vecAdd(&ret, b); + return copyVariableToPtr(ret); +} + +ClassFunction(stdGetNcaType){ + int type = GetNcaType(args[0]->string.value); + return newIntVariablePtr(type); +} #else ClassFunction(stdMountSysmmc){ return newIntVariablePtr(0); @@ -132,12 +209,29 @@ ClassFunction(stdMountSave){ ClassFunction(stdSetPixel) { return newIntVariablePtr(0); } + +ClassFunction(stdReadDir){ + return newIntVariablePtr(0); +} + +ClassFunction(stdFileCopy){ + return newIntVariablePtr(0); +} + +ClassFunction(stdMkdir){ + return newIntVariablePtr(0); +} + +ClassFunction(stdGetMemUsage) { + return newIntVariablePtr(0); +} #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; u8 oneStringArgStd[] = {StringClass}; u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; +u8 twoStringArgStd[] = {StringClass, StringClass}; ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"if", stdIf, 2, oneIntoneFunction}, @@ -150,6 +244,11 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"break", stdBreak, 0, 0}, {"dict", stdDict, 0, 0}, {"setpixel", stdSetPixel, 3, threeIntsStd}, + {"readdir", stdReadDir, 1, oneStringArgStd}, + {"filecopy", stdFileCopy, 2, twoStringArgStd}, + {"mkdir", stdMkdir, 1, oneStringArgStd}, + {"memory", stdGetMemUsage, 0, 0}, + {"ncatype", stdGetNcaType, 1, oneStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 16fccf5..2e5db63 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -22,7 +22,7 @@ #include #include "../fs/menus/filemenu.h" -//#define INCLUDE_BUILTIN_SCRIPTS 1 +#define INCLUDE_BUILTIN_SCRIPTS 1 #ifdef INCLUDE_BUILTIN_SCRIPTS #include "../script/builtin.h" @@ -121,11 +121,10 @@ void ViewCredits(){ if (hidRead()->r) gfx_printf("%k\"I'm not even sure if it works\" - meme", COLOR_ORANGE); -/* Leaving this here for my debugging needs :) heap_monitor_t a = {0}; heap_monitor(&a, false); gfx_printf("\nUsed: %d\nTotal: %d\n", a.used, a.total); -*/ + hidWait(); } From 9b47a0da3327b1d4296d4f94b4b5501708e8a297 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Thu, 22 Jul 2021 17:23:59 +0200 Subject: [PATCH 16/62] Fix line counter maybe? --- source/script/eval.c | 2 +- source/script/scriptError.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/script/eval.c b/source/script/eval.c index 7de4649..63f49c9 100644 --- a/source/script/eval.c +++ b/source/script/eval.c @@ -128,7 +128,7 @@ Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback) { } } else { - SCRIPT_FATAL_ERR("[FATAL] Unexpected set!"); + SCRIPT_FATAL_ERR("Unexpected set!"); } return NULL; } diff --git a/source/script/scriptError.c b/source/script/scriptError.c index e85ee98..0a2d957 100644 --- a/source/script/scriptError.c +++ b/source/script/scriptError.c @@ -12,6 +12,6 @@ void printScriptError(u8 errLevel, char* 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); + gfx_printf("\nError occured on or near line %d\n", (u32)scriptCurrentLine); va_end(args); } \ No newline at end of file From b730c060c7f6e0c0521acc948b505c000522d492 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Thu, 22 Jul 2021 18:13:57 +0200 Subject: [PATCH 17/62] possibly fix parser instability?? --- source/script/eval.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/script/eval.c b/source/script/eval.c index 63f49c9..0e8c113 100644 --- a/source/script/eval.c +++ b/source/script/eval.c @@ -30,13 +30,14 @@ void exitRuntimeVars() { } vecFree(runtimeVars); + runtimeVars.count = 0; } -Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback) { +Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback, u8 possibleCallArg) { Variable_t* var = NULL; CallArgs_t* args = NULL; - if ((op + 1)->token == CallArgs) + if ((op + 1)->token == CallArgs && possibleCallArg) args = &(op + 1)->callArgs; if (op->token == BetweenBrackets) { @@ -221,7 +222,7 @@ Variable_t* eval(Operator_t* ops, u32 len, u8 ret) { SCRIPT_FATAL_ERR("First token is not a variable"); } else { - curRes = opToVar(cur, &set); + curRes = opToVar(cur, &set, (len - i) > 1); if (!curRes) { if ((set.varName != NULL || set.idxVar != NULL) && set.hasBeenNoticed == 0) { set.hasBeenNoticed = 1; @@ -243,7 +244,7 @@ Variable_t* eval(Operator_t* ops, u32 len, u8 ret) { continue; } - Variable_t* rightSide = opToVar(cur, &set); + Variable_t* rightSide = opToVar(cur, &set, (len - i) > 1); if (!rightSide) return NULL; From e41971c7d682fbec69a2e214d7a44314a90e5eeb Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 01:10:03 +0200 Subject: [PATCH 18/62] safety push --- scripts/ButtonTest.te | 11 ++++ source/fs/menus/filemenu.c | 3 +- source/script/ABadIdeaVersion3.c | 31 +++++----- source/script/dictionaryClass.c | 11 ++++ source/script/dictionaryClass.h | 4 +- source/script/genericClass.c | 16 +++--- source/script/intClass.c | 8 ++- source/script/standardLibrary.c | 99 ++++++++++++++++++++++++++------ 8 files changed, 139 insertions(+), 44 deletions(-) create mode 100644 scripts/ButtonTest.te diff --git a/scripts/ButtonTest.te b/scripts/ButtonTest.te new file mode 100644 index 0000000..080614b --- /dev/null +++ b/scripts/ButtonTest.te @@ -0,0 +1,11 @@ +println("Testing pause") +x = pause() +println(x.raw, " ", x.a, "", x.power) +println("Testing masked pause") +x = pausemask(1 << 3) +println(x.raw, " ", x.a) +color(0xFF0000) +println("This text should be red!") +color(0x00FF00) +println("and this green!") +exit() \ No newline at end of file diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 43ae601..207cd88 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -77,8 +77,7 @@ void RunScriptString(char *str, u32 size){ ParserRet_t ret = parseScript(str, size); setStaticVars(&ret.staticVarHolder); initRuntimeVars(); - Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); - + eval(ret.main.operations.data, ret.main.operations.count, 0); exitRuntimeVars(); exitStaticVars(&ret.staticVarHolder); exitFunction(ret.main.operations.data, ret.main.operations.count); diff --git a/source/script/ABadIdeaVersion3.c b/source/script/ABadIdeaVersion3.c index 5da3b17..c405666 100644 --- a/source/script/ABadIdeaVersion3.c +++ b/source/script/ABadIdeaVersion3.c @@ -62,27 +62,30 @@ int main() return; */ - 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, strlen(script)); + while (1) { + ParserRet_t ret = parseScript(script, strlen(script)); + + + setStaticVars(&ret.staticVarHolder); + initRuntimeVars(); + + Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); + + exitRuntimeVars(); + exitStaticVars(&ret.staticVarHolder); + exitFunction(ret.main.operations.data, ret.main.operations.count); + vecFree(ret.staticVarHolder); + vecFree(ret.main.operations); + } + + free(script); - - setStaticVars(&ret.staticVarHolder); - initRuntimeVars(); - - Variable_t* res = eval(ret.main.operations.data, ret.main.operations.count, 1); - - exitRuntimeVars(); - 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/dictionaryClass.c b/source/script/dictionaryClass.c index 242b141..07e5fd9 100644 --- a/source/script/dictionaryClass.c +++ b/source/script/dictionaryClass.c @@ -1,9 +1,20 @@ #include "dictionaryClass.h" #include #include "garbageCollector.h" +#include "intClass.h" u8 dictOneStrOneAll[] = { StringClass, VARARGCOUNT }; +void addVariableToDict(Variable_t *dict, char* name, Variable_t *add){ + Dict_t a = {.name = CpyStr(name), .var = add}; + vecAdd(&dict->dictionary.vector, a); +} + +void addIntToDict(Variable_t *dict, char* name, s64 integer){ + Variable_t *v = newIntVariablePtr(integer); + addVariableToDict(dict, name, v); +} + Dict_t* getEntry(Vector_t *v, char* name) { vecForEach(Dict_t*, dict, v) { if (!strcmp(name, dict->name)) { diff --git a/source/script/dictionaryClass.h b/source/script/dictionaryClass.h index 8cb5361..a744a7f 100644 --- a/source/script/dictionaryClass.h +++ b/source/script/dictionaryClass.h @@ -3,4 +3,6 @@ #include "genericClass.h" #include "compat.h" -Variable_t getDictMember(Variable_t* var, char* memberName); \ No newline at end of file +Variable_t getDictMember(Variable_t* var, char* memberName); +void addVariableToDict(Variable_t *dict, char* name, Variable_t *add); +void addIntToDict(Variable_t *dict, char* name, s64 integer); \ No newline at end of file diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 9dde959..08053c6 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -63,7 +63,6 @@ Variable_t* genericGet(Variable_t* var, CallArgs_t* ref) { if (solvedIdx->variableType != IntClass) { SCRIPT_FATAL_ERR("Index is not an integer"); - return NULL; } Variable_t* res = callMemberFunctionDirect(var, "get", &solvedIdx, 1); @@ -71,12 +70,13 @@ Variable_t* genericGet(Variable_t* var, CallArgs_t* ref) { return res; } - return NULL; + SCRIPT_FATAL_ERR("???"); } Variable_t* genericCallDirect(Variable_t* var, Variable_t** args, u8 len) { - if (var->variableType != FunctionClass) - return NULL; + if (var->variableType != FunctionClass){ + SCRIPT_FATAL_ERR("Call on non function class"); + } if (var->function.builtIn) { for (u32 i = 0; i < var->function.len; i++) { @@ -109,8 +109,9 @@ Variable_t* genericCallDirect(Variable_t* var, Variable_t** args, u8 len) { } Variable_t* genericCall(Variable_t* var, CallArgs_t* ref) { - if (var->variableType != FunctionClass) - return NULL; + if (var->variableType != FunctionClass){ + SCRIPT_FATAL_ERR("Call on non function class"); + } if (var->function.builtIn) { // TODO: implement arg handling @@ -228,7 +229,7 @@ Variable_t* callMemberFunction(Variable_t* var, char* memberName, CallArgs_t* ar } } - return NULL; + SCRIPT_FATAL_ERR("Could not find function table for given type"); } Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable_t** args, u8 argsLen) { @@ -249,7 +250,6 @@ Variable_t* callMemberFunctionDirect(Variable_t* var, char* memberName, Variable } SCRIPT_FATAL_ERR("Could not find function table for given type"); - return NULL; } void freeVariableInternal(Variable_t* referencedTarget) { diff --git a/source/script/intClass.c b/source/script/intClass.c index 065356b..b569832 100644 --- a/source/script/intClass.c +++ b/source/script/intClass.c @@ -3,7 +3,9 @@ #include "compat.h" #include #include +#ifndef WIN32 #include +#endif IntClass_t createIntClass(s64 in) { IntClass_t a = { in }; @@ -23,9 +25,13 @@ ClassFunction(printIntVariable) { } ClassFunction(intToStr) { - char buff[64] = {0}; +#ifndef WIN32 + char buff[64] = { 0 }; s_printf(buff, "%d", getIntValue(caller)); return newStringVariablePtr(CpyStr(buff), 0, 1); +#else + return newIntVariablePtr(0); +#endif // !WIN32 } #define IntOpFunction(name, op) ClassFunction(name) { s64 i1 = getIntValue(caller); s64 i2 = getIntValue(*args); return newIntVariablePtr((i1 op i2)); } diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 6c26dd8..6a29e33 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -7,6 +7,7 @@ #include "standardLibrary.h" #include "scriptError.h" #include +#include "dictionaryClass.h" #ifndef WIN32 #include "../storage/mountmanager.h" @@ -15,6 +16,7 @@ #include "../fs/fscopy.h" #include #include "../keys/nca.h" +#include "../hid/hid.h" #endif ClassFunction(stdIf) { @@ -109,6 +111,7 @@ ClassFunction(stdMountSysmmc){ } ClassFunction(stdMountSave){ + Variable_t *arg = (*args); Variable_t var = {.variableType = SaveClass}; SaveClass_t* save = calloc(1, sizeof(SaveClass_t)); @@ -120,6 +123,8 @@ ClassFunction(stdMountSave){ var.save = save; return copyVariableToPtr(var); + +return newIntVariablePtr(0); } ClassFunction(stdSetPixel) { u32 color = getIntValue(args[2]); @@ -128,10 +133,9 @@ ClassFunction(stdSetPixel) { } ClassFunction(stdReadDir){ - Vector_t dict = newVec(sizeof(Dict_t), 4); Variable_t* resPtr = newIntVariablePtr(0); - Dict_t temp = {.name = CpyStr("result"), .var = resPtr}; - vecAdd(&dict, temp); + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 4)}; + addVariableToDict(&ret, "result", resPtr); Variable_t fileNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; Variable_t dirNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; @@ -139,7 +143,6 @@ ClassFunction(stdReadDir){ DIR dir; if ((resPtr->integer.value = f_opendir(&dir, args[0]->string.value))){ - Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = dict}; return copyVariableToPtr(ret); } @@ -158,22 +161,69 @@ ClassFunction(stdReadDir){ f_closedir(&dir); - temp.name = CpyStr("files"); - temp.var = copyVariableToPtr(fileNamesArray); - vecAdd(&dict, temp); - - temp.name = CpyStr("folders"); - temp.var = copyVariableToPtr(dirNamesArray); - vecAdd(&dict, temp); + addVariableToDict(&ret, "files", copyVariableToPtr(fileNamesArray)); + addVariableToDict(&ret, "folders", copyVariableToPtr(dirNamesArray)); + addVariableToDict(&ret, "fileSizes", copyVariableToPtr(fileSizeArray)); - temp.name = CpyStr("fileSizes"); - temp.var = copyVariableToPtr(fileSizeArray); - vecAdd(&dict, temp); - - Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = dict}; return copyVariableToPtr(ret); } +char *abxyNames[] = { + "y", + "x", + "b", + "a" +}; + +char *ulrdNames[] = { + "down", + "up", + "right", + "left", +}; + +char *powNames[] = { + "power", + "volplus", + "volminus", +}; + +ClassFunction(stdPauseMask){ + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 9)}; + Input_t *i = hidWaitMask((u32)getIntValue(*args)); + + u32 raw = i->buttons; + + addIntToDict(&ret, "raw", raw); + + for (int i = 0; i < ARRAY_SIZE(abxyNames); i++){ + addIntToDict(&ret, abxyNames[i], raw & 0x1); + raw >>= 1; + } + + raw >>= 12; + + for (int i = 0; i < ARRAY_SIZE(ulrdNames); i++){ + addIntToDict(&ret, ulrdNames[i], raw & 0x1); + raw >>= 1; + } + + raw >>= 4; + + for (int i = 0; i < ARRAY_SIZE(powNames); i++){ + addIntToDict(&ret, powNames[i], raw & 0x1); + raw >>= 1; + } + + return copyVariableToPtr(ret); +} + +ClassFunction(stdPause){ + Variable_t a = {.integer.value = 0xFFFFFFFF}; + Variable_t *b = &a; + return stdPauseMask(caller, &b, 1); +} + ClassFunction(stdFileCopy){ ErrCode_t e = FileCopy(args[0]->string.value, args[1]->string.value, 0); return newIntVariablePtr(e.err); @@ -190,11 +240,16 @@ ClassFunction(stdGetMemUsage){ Dict_t a = {.name = CpyStr("used"), .var = newIntVariablePtr((s64)mon.used)}; Dict_t b = {.name = CpyStr("total"), .var = newIntVariablePtr((s64)mon.total)}; Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 2)}; - vecAdd(&ret, a); - vecAdd(&ret, b); + vecAdd(&ret.dictionary.vector, a); + vecAdd(&ret.dictionary.vector, b); return copyVariableToPtr(ret); } +ClassFunction(stdColor){ + gfx_con_setcol((u32)getIntValue(*args) | 0xFF000000, gfx_con.fillbg, gfx_con.bgcol); + return &emptyClass; +} + ClassFunction(stdGetNcaType){ int type = GetNcaType(args[0]->string.value); return newIntVariablePtr(type); @@ -225,6 +280,10 @@ ClassFunction(stdMkdir){ ClassFunction(stdGetMemUsage) { return newIntVariablePtr(0); } + +ClassFunction(stdGetNcaType) { + return newIntVariablePtr(0); +} #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -232,6 +291,7 @@ u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; u8 oneStringArgStd[] = {StringClass}; u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; u8 twoStringArgStd[] = {StringClass, StringClass}; +u8 oneIntStd[] = {IntClass}; ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"if", stdIf, 2, oneIntoneFunction}, @@ -249,6 +309,9 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"mkdir", stdMkdir, 1, oneStringArgStd}, {"memory", stdGetMemUsage, 0, 0}, {"ncatype", stdGetNcaType, 1, oneStringArgStd}, + {"pause", stdPause, 0, 0}, + {"pausemask", stdPauseMask, 1, oneIntStd}, + {"color", stdColor, 1, oneIntStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName) { From 6543a245c4f7381de255feb31cba9287f8ddc799 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 14:02:25 +0200 Subject: [PATCH 19/62] build properly after clean on windows --- Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 670b9f0..716d464 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ BIN2CDIR := ./tools/bin2c VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) -OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ +OBJS = $(BUILDDIR)/$(TARGET)/script/builtin.c $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \ $(call rwildcard, $(SOURCEDIR), *.S *.c))) OBJS += $(patsubst $(BDKDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ @@ -104,6 +104,11 @@ $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c $(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S @mkdir -p "$(@D)" $(CC) $(CFLAGS) -c $< -o $@ - -$(SOURCEDIR)/script/builtin.c: scripts/*.te - @py te2c.py source/script/builtin scripts + +$(BUILDDIR)/$(TARGET)/script/builtin.o: $(BUILDDIR)/$(TARGET)/script/builtin.c + @mkdir -p "$(@D)" + $(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/script/builtin.c: scripts/*.te + @mkdir -p "$(@D)" + @py te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" scripts From 5bd4dd3a48a29f7228d4167267857e5fcc0f5478 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 14:03:49 +0200 Subject: [PATCH 20/62] add comments, fix std bugs, add menu --- scripts/ButtonTest.te | 8 ++- scripts/HelloWorld.te | 2 +- source/script/ABadIdeaVersion3.c | 4 +- source/script/compat.h | 2 +- source/script/eval.c | 2 + source/script/model.h | 5 +- source/script/parser.c | 6 +- source/script/standardLibrary.c | 97 +++++++++++++++++++++++++++++--- source/script/standardLibrary.h | 2 +- source/tegraexplorer/mainmenu.c | 2 +- 10 files changed, 111 insertions(+), 19 deletions(-) diff --git a/scripts/ButtonTest.te b/scripts/ButtonTest.te index 080614b..ff03605 100644 --- a/scripts/ButtonTest.te +++ b/scripts/ButtonTest.te @@ -2,10 +2,16 @@ println("Testing pause") x = pause() println(x.raw, " ", x.a, "", x.power) println("Testing masked pause") -x = pausemask(1 << 3) +x = pause(1 << 3) println(x.raw, " ", x.a) color(0xFF0000) println("This text should be red!") color(0x00FF00) println("and this green!") + +COLOR_RED = 0xFF0000 +COLOR_BLUE = 0x0000FF + +menu(["a", "b", "c"], 1, [COLOR_BLUE, COLOR_RED | 0x1000000, COLOR_BLUE]).print() + exit() \ No newline at end of file diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te index e373aaa..d58366f 100644 --- a/scripts/HelloWorld.te +++ b/scripts/HelloWorld.te @@ -19,4 +19,4 @@ println(a.fileSizes.len()) a.files.foreach("b") { println(b) -} \ No newline at end of file +} \ No newline at end of file diff --git a/source/script/ABadIdeaVersion3.c b/source/script/ABadIdeaVersion3.c index c405666..9fdcba5 100644 --- a/source/script/ABadIdeaVersion3.c +++ b/source/script/ABadIdeaVersion3.c @@ -68,7 +68,7 @@ int main() //parseScript("#REQUIRE VER 3.0.5\nmain = { two = 1 + 1 }"); //ParserRet_t ret = parseScript("a.b.c(1){ a.b.c() }"); - while (1) { + //while (1) { ParserRet_t ret = parseScript(script, strlen(script)); @@ -82,7 +82,7 @@ int main() exitFunction(ret.main.operations.data, ret.main.operations.count); vecFree(ret.staticVarHolder); vecFree(ret.main.operations); - } + //} free(script); diff --git a/source/script/compat.h b/source/script/compat.h index 0c594c5..57f1250 100644 --- a/source/script/compat.h +++ b/source/script/compat.h @@ -11,7 +11,7 @@ #define LP_VER_BF 5 #define LP_VER "3.0.5" #define FREE(x) if (x) free(x) - #define CpyStr(x) _strdup(x); + #define CpyStr(x) _strdup(x) #include "vector.h" #pragma _CRT_SECURE_NO_WARNINGS #else diff --git a/source/script/eval.c b/source/script/eval.c index 0e8c113..c80bb3c 100644 --- a/source/script/eval.c +++ b/source/script/eval.c @@ -69,7 +69,9 @@ Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback, u8 possibleC } else if (op->variable.staticVariableType == 3) { var = copyVariableToPtr(newFunctionVariable(createFunctionClass((Function_t) { 0 }, op->variable.staticFunction))); + var->function.len = op->variable.staticFunctionLen; var->reference = 1; + if (!strcmp(var->function.builtInPtr->name,"while")) { var->function.firstArgAsFunction = 1; diff --git a/source/script/model.h b/source/script/model.h index d2596d1..e9d2b2e 100644 --- a/source/script/model.h +++ b/source/script/model.h @@ -229,7 +229,10 @@ typedef struct _VariableReference_t { Array_t betweenBrackets; s64 integerType; char* stringType; - ClassFunctionTableEntry_t* staticFunction; + struct { + ClassFunctionTableEntry_t* staticFunction; + u8 staticFunctionLen; + }; }; } VariableReference_t; diff --git a/source/script/parser.c b/source/script/parser.c index 100a73e..e335762 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -320,15 +320,15 @@ ParserRet_t parseScript(char* in, u32 len) { } if (tokenType == Token_Variable) { - - ClassFunctionTableEntry_t* cfte = searchStdLib(var); + u8 stdLen = 0; + ClassFunctionTableEntry_t* cfte = searchStdLib(var, &stdLen); if (cfte == NULL) { CreateVariableReferenceStr(var); op.variable = reference; } else { - VariableReference_t reference = { .staticVariableType = 3, .staticFunction = cfte }; + VariableReference_t reference = { .staticVariableType = 3, .staticFunction = cfte, .staticFunctionLen = stdLen }; op.variable = reference; } } diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 6a29e33..7779c88 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -17,8 +17,10 @@ #include #include "../keys/nca.h" #include "../hid/hid.h" +#include "../gfx/menu.h" +#include "../gfx/gfxutils.h" #endif - +// Takes [int, function]. Returns elseable. ClassFunction(stdIf) { s64 value = getIntValue(args[0]); @@ -36,6 +38,7 @@ ClassFunction(stdIf) { return ret; } +// Takes [function, function]. Returns empty. Works by evaling the first function and running the 2nd if true. 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) @@ -65,6 +68,7 @@ ClassFunction(stdWhile) { return &emptyClass; } +// Takes [???]. Returns empty. Works by calling .print on every argument ClassFunction(stdPrint) { for (int i = 0; i < argsLen; i++) { Variable_t* res = callMemberFunctionDirect(args[i], "print", NULL, 0); @@ -76,21 +80,25 @@ ClassFunction(stdPrint) { return &emptyClass; } +// Takes [???]. Returns empty. Calls stdPrint ClassFunction(stdPrintLn) { stdPrint(caller, args, argsLen); gfx_printf("\n"); return &emptyClass; } +// Takes none. Returns none. Returning NULL will cause a cascade of errors and will exit runtime ClassFunction(stdExit) { return NULL; } +// Takes none. Returns none. See stdExit. stdWhile and array.foreach look for SCRIPT_BREAK and break when seen. ClassFunction(stdBreak) { scriptLastError = SCRIPT_BREAK; return NULL; } +// Takes none. Returns empty dictionary. ClassFunction(stdDict) { Variable_t a = { 0 }; a.variableType = DictionaryClass; @@ -99,6 +107,7 @@ ClassFunction(stdDict) { } #ifndef WIN32 +// Takes [str]. Returns int (0=success). str=partition to mount ClassFunction(stdMountSysmmc){ if (connectMMC(MMC_CONN_EMMC)) return newIntVariablePtr(1); @@ -110,6 +119,7 @@ ClassFunction(stdMountSysmmc){ return newIntVariablePtr(0); } +// Takes [str]. Returns int (0=success) str=path to save ClassFunction(stdMountSave){ Variable_t *arg = (*args); @@ -123,15 +133,16 @@ ClassFunction(stdMountSave){ var.save = save; return copyVariableToPtr(var); - -return newIntVariablePtr(0); } + +// Takes [int, int, int]. Returns empty. 0: posX, 1: posY, 2: hexColor ClassFunction(stdSetPixel) { u32 color = getIntValue(args[2]); gfx_set_pixel_horz(args[0]->integer.value, args[1]->integer.value, color); return &emptyClass; } +// Takes [str]. Returns empty. str: path to dir ClassFunction(stdReadDir){ Variable_t* resPtr = newIntVariablePtr(0); Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 4)}; @@ -188,6 +199,7 @@ char *powNames[] = { "volminus", }; +// Takes [int]. Returns dict[a,b,x,y,down,up,right,left,power,volplus,volminus,raw]. int: mask for hidWaitMask ClassFunction(stdPauseMask){ Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 9)}; Input_t *i = hidWaitMask((u32)getIntValue(*args)); @@ -218,12 +230,14 @@ ClassFunction(stdPauseMask){ return copyVariableToPtr(ret); } +// Takes none. Returns dict (same as stdPauseMask). ClassFunction(stdPause){ Variable_t a = {.integer.value = 0xFFFFFFFF}; Variable_t *b = &a; return stdPauseMask(caller, &b, 1); } +// Takes [str, str]. Returns int (0=success). 0: src path, 1: dst path ClassFunction(stdFileCopy){ ErrCode_t e = FileCopy(args[0]->string.value, args[1]->string.value, 0); return newIntVariablePtr(e.err); @@ -245,16 +259,62 @@ ClassFunction(stdGetMemUsage){ return copyVariableToPtr(ret); } +// Takes [int]. Returns empty. int: hex color ClassFunction(stdColor){ gfx_con_setcol((u32)getIntValue(*args) | 0xFF000000, gfx_con.fillbg, gfx_con.bgcol); return &emptyClass; } +// Takes [str]. Returns int. str: path to nca ClassFunction(stdGetNcaType){ int type = GetNcaType(args[0]->string.value); return newIntVariablePtr(type); } + +// Takes [str[], int, int[]]. Returns int (index). str[]: names of entries, int: starting index, int[]: colors & options. The 3rd argument is optional +ClassFunction(stdMenuFull){ + if (argsLen > 2){ + if (args[2]->solvedArray.vector.count < args[0]->solvedArray.vector.count){ + SCRIPT_FATAL_ERR("invalid menu args"); + } + } + + Vector_t v = newVec(sizeof(MenuEntry_t), args[0]->solvedArray.vector.count); + + vecDefArray(char**, menuEntryNames, args[0]->solvedArray.vector); + vecDefArray(s64*, menuEntryOptions, args[2]->solvedArray.vector); + + for (int i = 0; i < args[0]->solvedArray.vector.count; i++){ + MenuEntry_t a = {.name = menuEntryNames[i]}; + if (argsLen > 2){ + u32 options = (u32)menuEntryOptions[i]; + if (options & BIT(26)){ + a.icon = 128; + } + else if (options & BIT(27)){ + a.icon = 127; + } + + a.optionUnion = options; + } + else { + a.optionUnion = COLORTORGB(COLOR_WHITE); + } + + vecAdd(&v, a); + } + + u32 x=0,y=0; + gfx_con_getpos(&x,&y); + + int res = newMenu(&v, getIntValue(args[1]), ScreenDefaultLenX - ((x + 1) / 16), ScreenDefaultLenY - ((y + 1) / 16) - 1, ENABLEB | ALWAYSREDRAW, 0); + vecFree(v); + return newIntVariablePtr(res); +} + #else +#define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } + ClassFunction(stdMountSysmmc){ return newIntVariablePtr(0); } @@ -284,6 +344,11 @@ ClassFunction(stdGetMemUsage) { ClassFunction(stdGetNcaType) { return newIntVariablePtr(0); } + +STUBBED(stdPause) +STUBBED(stdPauseMask) +STUBBED(stdColor) +STUBBED(stdMenuFull) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -292,6 +357,7 @@ u8 oneStringArgStd[] = {StringClass}; u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; u8 twoStringArgStd[] = {StringClass, StringClass}; u8 oneIntStd[] = {IntClass}; +u8 menuArgsStd[] = {StringArrayClass, IntClass, IntArrayClass}; ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"if", stdIf, 2, oneIntoneFunction}, @@ -309,16 +375,31 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"mkdir", stdMkdir, 1, oneStringArgStd}, {"memory", stdGetMemUsage, 0, 0}, {"ncatype", stdGetNcaType, 1, oneStringArgStd}, + {"pause", stdPauseMask, 1, oneIntStd}, {"pause", stdPause, 0, 0}, - {"pausemask", stdPauseMask, 1, oneIntStd}, {"color", stdColor, 1, oneIntStd}, + {"menu", stdMenuFull, 3, menuArgsStd}, + {"menu", stdMenuFull, 2, menuArgsStd}, }; -ClassFunctionTableEntry_t* searchStdLib(char* funcName) { +ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { + u8 lenInternal = 0; + *len = 0; + ClassFunctionTableEntry_t *ret = NULL; + for (int i = 0; i < ARRAY_SIZE(standardFunctionDefenitions); i++) { - if (!strcmp(funcName, standardFunctionDefenitions[i].name)) - return &standardFunctionDefenitions[i]; + if (!strcmp(funcName, standardFunctionDefenitions[i].name)) { + lenInternal++; + if (ret == NULL){ + ret = &standardFunctionDefenitions[i]; + } + } + else if (lenInternal != 0){ + *len = lenInternal; + return ret; + } } - return NULL; + *len = lenInternal; + return ret; } \ No newline at end of file diff --git a/source/script/standardLibrary.h b/source/script/standardLibrary.h index 6f92c8a..bab6837 100644 --- a/source/script/standardLibrary.h +++ b/source/script/standardLibrary.h @@ -1,4 +1,4 @@ #pragma once #include "model.h" -ClassFunctionTableEntry_t* searchStdLib(char* funcName); \ No newline at end of file +ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len); \ No newline at end of file diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 2e5db63..68d134b 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -25,7 +25,7 @@ #define INCLUDE_BUILTIN_SCRIPTS 1 #ifdef INCLUDE_BUILTIN_SCRIPTS -#include "../script/builtin.h" +#include "../../build/TegraExplorer/script/builtin.h" #endif extern hekate_config h_cfg; From 60eac955f62674588f3793f2d27cd9d54b81f349 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 16:06:52 +0200 Subject: [PATCH 21/62] make fwdump.te significantly more cursed --- scripts/FirmwareDump.te | 127 ++++++++++++++------------------ source/script/StringClass.c | 10 +++ source/script/standardLibrary.c | 57 ++++++++++++-- 3 files changed, 115 insertions(+), 79 deletions(-) diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index 1a56086..ce3c8be 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -1,77 +1,58 @@ -if (mountsys("SYSTEM")){ - print("SYSTEM MOUNT FAIL") - exit() -} - -a = readsave("bis:/save/8000000000000120") -b = a.readFile("/meta/imkvdb.arc") -print(b.len(), "\n") - -c = ["BYTE[]", 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01] - -i = 1 -#while (i + c.len() < b.len()){ -# if (b.slice(i, 8).project() == c) {\ - -fuck = b.find(c) -if (fuck < 0) { - print("Not found") - exit() -} - -i = fuck - -d = b.slice(i + 8, 4).project() -ver = (d[3] << 24) | (d[2] << 16) | (d[1] << 8) | (d[0]) -rev = (ver & ((1 << 16) - 1)) -pat = ((ver >> 16) & ((1 << 4) - 1)) -min = ((ver >> 20) & ((1 << 6) - 1)) -maj = ((ver >> 26) & ((1 << 6) - 1)) -print("") -println(ver.str(), " ", maj.str(), ".", min.str(), ".", pat.str(), ".", rev.str()) - - -# i = i + 1 -#} - - +#REQUIRE KEYS +p=println +pe={pause() exit()} +fwstr={fw=maj.str()+"."+min.str()+"."+pat.str()} +fv={a=readsave("bis:/save/8000000000000120") + b=a.readFile("/meta/imkvdb.arc") + c=["BYTE[]",9,8,0,0,0,0,0,1] + d=b.find(c) + if(d>0){ + e=b.slice(d+8,4).project() + ver=(e[3]<<24)|(e[2]<<16)|(e[1]<<8)|(e[0]) + pat=((ver>>16)&((1<<4)- 1)) + min=((ver>>20)&((1<<6)- 1)) + maj=((ver>>26)&((1<<6)- 1)) + }.else(){print("Fw not found")pe()} + a=0 fwstr()} +if(mountsys("SYSTEM")){print("SYSTEM MOUNT FAIL")pe()} +fv() +sysfw=fw +p("Sys' fw is",fw) +emufw="" +if (emu()){if(!mountemu("SYSTEM")){ + fv() + emufw=fw + p("Emu's fw is",fw)}} +op=["Exit","Dump sysmmc"].copy() +if (emufw!=""){op+"Dump emummc"} +p() +r=menu(op,0) +if(r==0){exit()} +if(r==1){fw=sysfw if(mountsys("SYSTEM")){print("SYSTEM MOUNT FAIL")pe()}} +if(r==2){fw=emufw if(mountemu("SYSTEM")){print("SYSTEM MOUNT FAIL")pe()}} +clear() mkdir("sd:/tegraexplorer") mkdir("sd:/tegraexplorer/Firmware") -baseSdPath = "sd:/tegraexplorer/Firmware/" + maj.str() + "." + min.str() + "." + pat.str() -mkdir(baseSdPath) - -contents = readdir("bis:/Contents/registered") -if (contents.result != 0){ - println("Fail reading dir") - exit() -} - -contents.files.foreach("x") { - fullPath = "bis:/Contents/registered/" + x - name = x - if (ncatype(fullPath) == 1){ - name = name - 4 + ".cnmt.nca" - } - print("\r", x) - fullSdPath = baseSdPath + "/" + name - if (filecopy(fullPath, fullSdPath)){ - println("\nErr during copy") - exit() +bsp = "sd:/tegraexplorer/Firmware/" + fw +if(fsexists(bsp)){p("Dir already exists! Press power to replace, any other key to exit") a=pause() if (!a.power){exit()} deldir(bsp)} +mkdir(bsp) +p("Dumping to",bsp) +con=readdir("bis:/Contents/registered") +if(con.result!=0){println("Fail reading dir")pe()} +c=(con.files.len()+con.folders.len()).str() +i=1 f=0 t=timer() +dump={ + fi.foreach("x"){ + if(f){fp="bis:/Contents/registered/"+x+"/00"} + .else(){fp="bis:/Contents/registered/"+x} + name=x + if(ncatype(fp)==1){name=name- 4+".cnmt.nca"} + color(0x00FF00) + print("\r["+i.str()+"/"+c+"]", x) + if(filecopy(fp,bsp+"/"+name)){println("\nErr during copy")pe()} + i=i+1 } } - -contents.folders.foreach("x") { - fullPath = "bis:/Contents/registered/" + x + "/00" - name = x - if (ncatype(fullPath) == 1){ - name = name - 4 + ".cnmt.nca" - } - print("\r", x) - fullSdPath = baseSdPath + "/" + name - if (filecopy(fullPath, fullSdPath)){ - println("\nErr during copy") - exit() - } -} - -print("end") \ No newline at end of file +fi=con.files dump() +f=1 fi=con.folders dump() +p("\nDone! Took",timer()-t/1000,"s") \ No newline at end of file diff --git a/source/script/StringClass.c b/source/script/StringClass.c index c5cf5df..1180421 100644 --- a/source/script/StringClass.c +++ b/source/script/StringClass.c @@ -80,6 +80,14 @@ ClassFunction(stringMinusInt){ return newStringVariablePtr(newStr, 0, 1); } +ClassFunction(stringEq){ + return newIntVariablePtr(!strcmp(caller->string.value, args[0]->string.value)); +} + +ClassFunction(stringInEq){ + return newIntVariablePtr(strcmp(caller->string.value, args[0]->string.value)); +} + u8 strOneIntArg[] = { IntClass }; u8 oneStringArg[] = { StringClass }; @@ -90,6 +98,8 @@ ClassFunctionTableEntry_t stringFunctions[] = { {"bytes", stringBytes, 0, 0}, {"get", stringIndexGet, 1, strOneIntArg}, {"-", stringMinusInt, 1, strOneIntArg}, + {"==", stringEq, 1, oneStringArg}, + {"!=", stringInEq, 1, oneStringArg}, }; Variable_t getStringMember(Variable_t* var, char* memberName) { diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 7779c88..2b730a2 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -19,6 +19,10 @@ #include "../hid/hid.h" #include "../gfx/menu.h" #include "../gfx/gfxutils.h" +#include "../tegraexplorer/tconf.h" +#include "../storage/emummc.h" +#include +#include "../fs/fsutils.h" #endif // Takes [int, function]. Returns elseable. ClassFunction(stdIf) { @@ -74,6 +78,7 @@ ClassFunction(stdPrint) { Variable_t* res = callMemberFunctionDirect(args[i], "print", NULL, 0); if (res == NULL) return NULL; + gfx_putc(' '); } @@ -107,16 +112,29 @@ ClassFunction(stdDict) { } #ifndef WIN32 + + +int mountMmc(u8 mmc, char *part){ + if (connectMMC(mmc)) + return 1; + + if (mountMMCPart(part).err) + return 1; + + return 0; +} + // Takes [str]. Returns int (0=success). str=partition to mount ClassFunction(stdMountSysmmc){ - if (connectMMC(MMC_CONN_EMMC)) - return newIntVariablePtr(1); + return newIntVariablePtr(mountMmc(MMC_CONN_EMMC, args[0]->string.value)); +} - Variable_t *arg = (*args); - if (mountMMCPart(arg->string.value).err) - return newIntVariablePtr(1); // Maybe change for error? +ClassFunction(stdMountEmummc){ + if (!emu_cfg.enabled){ + SCRIPT_FATAL_ERR("emummc is not enabled"); + } - return newIntVariablePtr(0); + return newIntVariablePtr(mountMmc(MMC_CONN_EMUMMC, args[0]->string.value)); } // Takes [str]. Returns int (0=success) str=path to save @@ -312,6 +330,27 @@ ClassFunction(stdMenuFull){ return newIntVariablePtr(res); } +ClassFunction(stdHasEmu){ + return newIntVariablePtr(emu_cfg.enabled); +} + +ClassFunction(stdClear){ + gfx_clearscreen(); + return &emptyClass; +} + +ClassFunction(stdRmDir){ + return newIntVariablePtr(FolderDelete(args[0]->string.value).err); +} + +ClassFunction(stdGetMs){ + return newIntVariablePtr(get_tmr_ms()); +} + +ClassFunction(stdFileExists){ + return newIntVariablePtr(FileExists(args[0]->string.value)); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -365,6 +404,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"print", stdPrint, VARARGCOUNT, 0}, {"println", stdPrintLn, VARARGCOUNT, 0}, {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, + {"mountemu", stdMountEmummc, 1, oneStringArgStd}, {"readsave", stdMountSave, 1, oneStringArgStd}, {"exit", stdExit, 0, 0}, {"break", stdBreak, 0, 0}, @@ -380,6 +420,11 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"color", stdColor, 1, oneIntStd}, {"menu", stdMenuFull, 3, menuArgsStd}, {"menu", stdMenuFull, 2, menuArgsStd}, + {"emu", stdHasEmu, 0, 0}, + {"clear", stdClear, 0, 0}, + {"timer", stdGetMs, 0, 0}, + {"deldir", stdRmDir, 1, oneStringArgStd}, + {"fsexists", stdFileExists, 1, oneStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { From f5623a4fdc3b46b43c4c5693c69729582951242d Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 16:09:53 +0200 Subject: [PATCH 22/62] F to Dump Firmware --- source/tegraexplorer/mainmenu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 68d134b..f78fdff 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -38,7 +38,6 @@ enum { MainBrowseEmummc, MainTools, MainPartitionSd, - MainDumpFw, MainViewKeys, MainViewCredits, MainExit, @@ -58,7 +57,6 @@ MenuEntry_t mainMenuEntries[] = { [MainBrowseEmummc] = {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "Browse EMUMMC"}, [MainTools] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "\n-- Tools --"}, [MainPartitionSd] = {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "Partition the sd"}, - [MainDumpFw] = {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "Dump Firmware"}, [MainViewKeys] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "View dumped keys"}, [MainViewCredits] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "Credits"}, [MainExit] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "\n-- Exit --"}, @@ -155,7 +153,6 @@ menuPaths mainMenuPaths[] = { [MainBrowseEmmc] = HandleEMMC, [MainBrowseEmummc] = HandleEMUMMC, [MainPartitionSd] = FormatSD, - [MainDumpFw] = DumpSysFw, [MainViewKeys] = ViewKeys, [MainRebootAMS] = RebootToAMS, [MainRebootHekate] = RebootToHekate, @@ -178,7 +175,6 @@ void EnterMainMenu(){ // -- Tools -- mainMenuEntries[MainPartitionSd].hide = (!is_sd_inited || sd_get_card_removed()); - mainMenuEntries[MainDumpFw].hide = (!TConf.keysDumped || !sd_mounted); mainMenuEntries[MainViewKeys].hide = !TConf.keysDumped; // -- Exit -- From 987b7e8765b65bdb93671eded48c401857e81b72 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 23 Jul 2021 16:19:32 +0200 Subject: [PATCH 23/62] fuk --- source/tegraexplorer/mainmenu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index f78fdff..b9ec3f1 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -234,8 +234,10 @@ void EnterMainMenu(){ res = newMenu(&ent, res, 79, 30, (ent.count == ARRAY_SIZE(mainMenuEntries)) ? ALWAYSREDRAW : ALWAYSREDRAW | ENABLEPAGECOUNT, ent.count - ARRAY_SIZE(mainMenuEntries)); if (res < MainScripts && mainMenuPaths[res] != NULL) mainMenuPaths[res](); + #ifndef INCLUDE_BUILTIN_SCRIPTS else if (hasScripts){ - #ifdef INCLUDE_BUILTIN_SCRIPTS + #else + else { if (res - ARRAY_SIZE(mainMenuEntries) < EMBEDDED_SCRIPTS_LEN){ char *script = embedded_scripts_g[res - ARRAY_SIZE(mainMenuEntries)].script; RunScriptString(script, strlen(script)); From f48447f9f51ac1095647805bad11eaa80722d362 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 24 Jul 2021 23:00:05 +0200 Subject: [PATCH 24/62] make Systemwipe.te --- scripts/FirmwareDump.te | 13 ++++--------- scripts/SystemWipe.te | 30 ++++++++++++++++++++++++++++++ source/script/arrayClass.c | 4 ++++ source/script/compat.h | 3 ++- source/script/standardLibrary.c | 14 +++++++++++++- 5 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 scripts/SystemWipe.te diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index ce3c8be..d3649b9 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -19,22 +19,17 @@ fv() sysfw=fw p("Sys' fw is",fw) emufw="" -if (emu()){if(!mountemu("SYSTEM")){ - fv() - emufw=fw - p("Emu's fw is",fw)}} +if (emu()){if(!mountemu("SYSTEM")){fv()emufw=fw p("Emu's fw is",fw)}} op=["Exit","Dump sysmmc"].copy() if (emufw!=""){op+"Dump emummc"} -p() -r=menu(op,0) +p()r=menu(op,0)clear() if(r==0){exit()} if(r==1){fw=sysfw if(mountsys("SYSTEM")){print("SYSTEM MOUNT FAIL")pe()}} if(r==2){fw=emufw if(mountemu("SYSTEM")){print("SYSTEM MOUNT FAIL")pe()}} -clear() mkdir("sd:/tegraexplorer") mkdir("sd:/tegraexplorer/Firmware") -bsp = "sd:/tegraexplorer/Firmware/" + fw -if(fsexists(bsp)){p("Dir already exists! Press power to replace, any other key to exit") a=pause() if (!a.power){exit()} deldir(bsp)} +bsp="sd:/tegraexplorer/Firmware/"+fw +if(fsexists(bsp)){p("Dir already exists! Press power to replace, any other key to exit") a=pause() if(!a.power){exit()} deldir(bsp)} mkdir(bsp) p("Dumping to",bsp) con=readdir("bis:/Contents/registered") diff --git a/scripts/SystemWipe.te b/scripts/SystemWipe.te new file mode 100644 index 0000000..e33506a --- /dev/null +++ b/scripts/SystemWipe.te @@ -0,0 +1,30 @@ +is=["8000000000000120","80000000000000d1","8000000000000047"] +p=println +pr=print +pe={pause() exit()} +wait={t=timer()while(timer()<(t+tw)){print("Wait for",(t+tw-timer()/1000),"seconds \r")}} +p("System wiper\n") +op=["Exit","Wipe sysmmc"].copy() +if (emu()){op+"Wipe emummc"} +r=menu(op,0)clear() +if(r==0){exit()} +if(r==1){p("Selected sysmmc")mount=mountsys} +if(r==2){p("Selected emummc")mount=mountemu} +if(mount("SYSTEM")){p("Mount failed!")pe()} +color(0xFF0000) +p("Are you sure you want to wipe everything?\nThis includes:\n- Saves\n- Game Data\n- All other data on the system\n\nUse this only as a last resort!") +color(0xFFFF00) +tw=10000 +wait() +color(0x0000FF) +p("Press power to wipe, any other key to exit")a=pause()if(!a.power){exit()}clear() +color(0xFF0000) +pr("Deleting system saves... ") +f=readdir("bis:/save") +if(f.folders.len()!=0){p("Folders in save dir???")pe()} +f.files.foreach("x"){if(!is.contains(x)){if(delfile("bis:/save/"+x)){p("File deletion failed: ", x)pe()}}} +pr("Done!\nDeleting user dirs...")ud=["Album","Contents","save","saveMeta","temp"] +if(mount("USER")){p("Mount failed!")pe()} +ud.foreach("x"){pr("\n"+x,"")if(deldir("bis:/"+x)){p("Dir deletion failed")pe()}mkdir("bis:/"+x)} +mkdir("bis:/Contents/placehld")mkdir("bis:/Contents/registered") +color(0x00FF00)p("\n\nDone!")pause() \ No newline at end of file diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index 4fbb9cf..44c2dc3 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -173,6 +173,10 @@ ClassFunction(arrayContains) { for (int i = 0; i < v->count; i++) { Variable_t iter = arrayClassGetIdx(caller, i); + + if (iter.variableType != arg->variableType){ + SCRIPT_FATAL_ERR("type of contains does not match"); + } if (caller->variableType == StringArrayClass) { if (!strcmp(arg->string.value, iter.string.value)) diff --git a/source/script/compat.h b/source/script/compat.h index 57f1250..c35cf6f 100644 --- a/source/script/compat.h +++ b/source/script/compat.h @@ -3,8 +3,9 @@ #ifdef WIN32 #include #include -#define gfx_printf(str, ...) printf(str, ##__VA_ARGS__) + #define gfx_printf(str, ...) printf(str, ##__VA_ARGS__) #define gfx_vprintf(str, va) vprintf(str, va); + #define gfx_putc(x) gfx_printf("%c", x) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) #define LP_VER_MJ 3 #define LP_VER_MN 0 diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 2b730a2..80d2df2 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -78,7 +78,8 @@ ClassFunction(stdPrint) { Variable_t* res = callMemberFunctionDirect(args[i], "print", NULL, 0); if (res == NULL) return NULL; - gfx_putc(' '); + if (i + 1 != argsLen) + gfx_putc(' '); } @@ -351,6 +352,10 @@ ClassFunction(stdFileExists){ return newIntVariablePtr(FileExists(args[0]->string.value)); } +ClassFunction(stdFileDel){ + return newIntVariablePtr(f_unlink(args[0]->string.value)); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -388,6 +393,12 @@ STUBBED(stdPause) STUBBED(stdPauseMask) STUBBED(stdColor) STUBBED(stdMenuFull) +STUBBED(stdMountEmummc) +STUBBED(stdHasEmu) +STUBBED(stdGetMs) +STUBBED(stdClear) +STUBBED(stdRmDir) +STUBBED(stdFileExists) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -425,6 +436,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"timer", stdGetMs, 0, 0}, {"deldir", stdRmDir, 1, oneStringArgStd}, {"fsexists", stdFileExists, 1, oneStringArgStd}, + {"delfile", stdFileDel, 1, oneStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { From 5b981bb144f3025107ef282b7140077199d2ded5 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 24 Jul 2021 23:05:09 +0200 Subject: [PATCH 25/62] remove pauses --- scripts/FirmwareDump.te | 2 +- source/fs/menus/filemenu.c | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index d3649b9..bc31922 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -50,4 +50,4 @@ dump={ } fi=con.files dump() f=1 fi=con.folders dump() -p("\nDone! Took",timer()-t/1000,"s") \ No newline at end of file +p("\nDone! Took",timer()-t/1000,"s")pause() \ No newline at end of file diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 207cd88..c46e376 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -83,9 +83,6 @@ void RunScriptString(char *str, u32 size){ exitFunction(ret.main.operations.data, ret.main.operations.count); vecFree(ret.staticVarHolder); vecFree(ret.main.operations); - - hidWait(); - hidWait(); } void RunScript(char *path, FSEntry_t entry){ @@ -114,25 +111,16 @@ void RunScript(char *path, FSEntry_t entry){ lexarVectorClear(&ctx.script); */ - gfx_printf("Parsing\n"); ParserRet_t ret = parseScript(script, size); 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(); 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){ From e423a612ce4b93936f1b6c56782733bef6a425d7 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 25 Jul 2021 00:54:21 +0200 Subject: [PATCH 26/62] a --- source/script/arrayClass.c | 1 + source/script/standardLibrary.c | 1 + 2 files changed, 2 insertions(+) diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index 44c2dc3..fdc10c1 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -257,6 +257,7 @@ ClassFunctionTableEntry_t arrayFunctions[] = { {"copy", arrayCopy, 0, 0}, {"set", arraySet, 2, oneIntOneAny}, {"+", arrayAdd, 1, anotherAnotherOneVarArg}, + {"add", arrayAdd, 1, anotherAnotherOneVarArg}, {"-", arrayMinus, 1, anotherOneIntArg}, {"contains", arrayContains, 1, anotherAnotherOneVarArg}, {"bytestostr", bytesToStr, 0, 0}, diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 80d2df2..c2d4c6b 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -399,6 +399,7 @@ STUBBED(stdGetMs) STUBBED(stdClear) STUBBED(stdRmDir) STUBBED(stdFileExists) +STUBBED(stdFileDel) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; From db3ba94b5a16e32150e863d16e6215168e82099f Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 25 Jul 2021 17:49:00 +0200 Subject: [PATCH 27/62] [Untested] implement some more fs functions --- scripts/FirmwareDump.te | 2 +- source/script/ABadIdeaVersion3.vcxproj | 3 + .../script/ABadIdeaVersion3.vcxproj.filters | 5 ++ source/script/standardLibrary.c | 84 +++++++++++++++---- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index bc31922..e41e29c 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -44,7 +44,7 @@ dump={ if(ncatype(fp)==1){name=name- 4+".cnmt.nca"} color(0x00FF00) print("\r["+i.str()+"/"+c+"]", x) - if(filecopy(fp,bsp+"/"+name)){println("\nErr during copy")pe()} + if(copyfile(fp,bsp+"/"+name)){println("\nErr during copy")pe()} i=i+1 } } diff --git a/source/script/ABadIdeaVersion3.vcxproj b/source/script/ABadIdeaVersion3.vcxproj index 53eb1d3..bcfb9f4 100644 --- a/source/script/ABadIdeaVersion3.vcxproj +++ b/source/script/ABadIdeaVersion3.vcxproj @@ -179,6 +179,9 @@ + + + diff --git a/source/script/ABadIdeaVersion3.vcxproj.filters b/source/script/ABadIdeaVersion3.vcxproj.filters index 26caa24..fa0362c 100644 --- a/source/script/ABadIdeaVersion3.vcxproj.filters +++ b/source/script/ABadIdeaVersion3.vcxproj.filters @@ -144,4 +144,9 @@ Source Files\Classes\Elseable + + + Source Files + + \ No newline at end of file diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index c2d4c6b..7896202 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -23,6 +23,7 @@ #include "../storage/emummc.h" #include #include "../fs/fsutils.h" +#include #endif // Takes [int, function]. Returns elseable. ClassFunction(stdIf) { @@ -356,6 +357,36 @@ ClassFunction(stdFileDel){ return newIntVariablePtr(f_unlink(args[0]->string.value)); } +ClassFunction(stdCopyDir){ + return newIntVariablePtr(FolderCopy(args[0]->string.value, args[1]->string.value).err); +} + +ClassFunction(stdFileMove){ + return newIntVariablePtr(f_rename(args[0]->string.value, args[1]->string.value)); +} + +ClassFunction(stdFileRead){ + u32 fSize = 0; + u8 *buff = sd_file_read(args[0]->string.value, &fSize); + if (buff == NULL){ + SCRIPT_FATAL_ERR("Failed to read file"); + } + + Vector_t vec = vecFromArray(buff, fSize, sizeof(u8)); + Variable_t v = {.variableType = ByteArrayClass, .solvedArray.vector = vec}; + return copyVariableToPtr(v); +} + +ClassFunction(stdFileWrite){ + return newIntVariablePtr(sd_save_to_file(args[1]->solvedArray.vector.data, args[1]->solvedArray.vector.count, args[0]->string.value)); +} + +extern int launch_payload(char *path); + +ClassFunction(stdLaunchPayload){ + return newIntVariablePtr(launch_payload(args[0]->string.value)); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -400,6 +431,11 @@ STUBBED(stdClear) STUBBED(stdRmDir) STUBBED(stdFileExists) STUBBED(stdFileDel) +STUBBED(stdCopyDir) +STUBBED(stdFileMove) +STUBBED(stdLaunchPayload) +STUBBED(stdFileWrite) +STUBBED(stdFileRead) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; @@ -409,35 +445,55 @@ u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; u8 twoStringArgStd[] = {StringClass, StringClass}; u8 oneIntStd[] = {IntClass}; u8 menuArgsStd[] = {StringArrayClass, IntClass, IntArrayClass}; +u8 oneStringOneByteArrayStd[] = {StringClass, ByteArrayClass}; ClassFunctionTableEntry_t standardFunctionDefenitions[] = { + // Flow control {"if", stdIf, 2, oneIntoneFunction}, {"while", stdWhile, 2, doubleFunctionClass}, - {"print", stdPrint, VARARGCOUNT, 0}, - {"println", stdPrintLn, VARARGCOUNT, 0}, - {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, - {"mountemu", stdMountEmummc, 1, oneStringArgStd}, - {"readsave", stdMountSave, 1, oneStringArgStd}, {"exit", stdExit, 0, 0}, {"break", stdBreak, 0, 0}, + + // Class creation + {"readsave", stdMountSave, 1, oneStringArgStd}, {"dict", stdDict, 0, 0}, - {"setpixel", stdSetPixel, 3, threeIntsStd}, - {"readdir", stdReadDir, 1, oneStringArgStd}, - {"filecopy", stdFileCopy, 2, twoStringArgStd}, - {"mkdir", stdMkdir, 1, oneStringArgStd}, + + // Utils + {"print", stdPrint, VARARGCOUNT, 0}, + {"println", stdPrintLn, VARARGCOUNT, 0}, + {"setpixel", stdSetPixel, 3, threeIntsStd}, // TODO: change for setblock + {"emu", stdHasEmu, 0, 0}, + {"clear", stdClear, 0, 0}, + {"timer", stdGetMs, 0, 0}, {"memory", stdGetMemUsage, 0, 0}, - {"ncatype", stdGetNcaType, 1, oneStringArgStd}, {"pause", stdPauseMask, 1, oneIntStd}, {"pause", stdPause, 0, 0}, {"color", stdColor, 1, oneIntStd}, {"menu", stdMenuFull, 3, menuArgsStd}, {"menu", stdMenuFull, 2, menuArgsStd}, - {"emu", stdHasEmu, 0, 0}, - {"clear", stdClear, 0, 0}, - {"timer", stdGetMs, 0, 0}, + + // System + {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, + {"mountemu", stdMountEmummc, 1, oneStringArgStd}, + {"ncatype", stdGetNcaType, 1, oneStringArgStd}, + + // FileSystem + // Dir + {"readdir", stdReadDir, 1, oneStringArgStd}, {"deldir", stdRmDir, 1, oneStringArgStd}, - {"fsexists", stdFileExists, 1, oneStringArgStd}, + {"mkdir", stdMkdir, 1, oneStringArgStd}, + {"copydir", stdCopyDir, 2, twoStringArgStd}, + + // File + {"copyfile", stdFileCopy, 2, twoStringArgStd}, + {"movefile", stdFileMove, 2, twoStringArgStd}, {"delfile", stdFileDel, 1, oneStringArgStd}, + {"readfile", stdFileRead, 1, oneStringArgStd}, + {"writefile", stdFileWrite, 2, oneStringOneByteArrayStd}, + + // Utils + {"fsexists", stdFileExists, 1, oneStringArgStd}, + {"payload", stdLaunchPayload, 1, oneStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { From 6ecf8daef776cc51c9e1c507980781c33b3ae0d4 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 25 Jul 2021 21:39:45 +0200 Subject: [PATCH 28/62] add str.split --- source/script/StringClass.c | 25 +++++++++++++++++++++++++ source/script/parser.h | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/source/script/StringClass.c b/source/script/StringClass.c index 1180421..9530453 100644 --- a/source/script/StringClass.c +++ b/source/script/StringClass.c @@ -2,6 +2,7 @@ #include "compat.h" #include "intClass.h" #include "scriptError.h" +#include "parser.h" #include char* getStringValue(Variable_t* var) { @@ -88,6 +89,28 @@ ClassFunction(stringInEq){ return newIntVariablePtr(strcmp(caller->string.value, args[0]->string.value)); } +ClassFunction(stringSplit) { + int valLen = strlen(args[0]->string.value); + + char* start = caller->string.value; + char* find = NULL; + Vector_t arr = newVec(sizeof(char**), 1); + char* temp; + + while ((find = (strstr(start, args[0]->string.value))) != NULL) { + temp = utils_copyStringSize(start, find - start); + vecAdd(&arr, temp); + + start = find + valLen; + } + + temp = utils_copyStringSize(start, caller->string.value + strlen(caller->string.value) - start); + vecAdd(&arr, temp); + + Variable_t a = { .variableType = StringArrayClass, .solvedArray.vector = arr }; + return copyVariableToPtr(a); +} + u8 strOneIntArg[] = { IntClass }; u8 oneStringArg[] = { StringClass }; @@ -100,6 +123,8 @@ ClassFunctionTableEntry_t stringFunctions[] = { {"-", stringMinusInt, 1, strOneIntArg}, {"==", stringEq, 1, oneStringArg}, {"!=", stringInEq, 1, oneStringArg}, + {"split", stringSplit, 1, oneStringArg}, + {"/", stringSplit, 1, oneStringArg}, }; Variable_t getStringMember(Variable_t* var, char* memberName) { diff --git a/source/script/parser.h b/source/script/parser.h index c81e3a2..51dc4d4 100644 --- a/source/script/parser.h +++ b/source/script/parser.h @@ -12,4 +12,5 @@ typedef struct { void exitStaticVars(Vector_t* v); void exitFunction(Operator_t* start, u32 len); -ParserRet_t parseScript(char* in, u32 len); \ No newline at end of file +ParserRet_t parseScript(char* in, u32 len); +char* utils_copyStringSize(const char* in, int size); \ No newline at end of file From dea329444526a29bfa607c31c74bc2a047a47cb1 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 25 Jul 2021 22:08:19 +0200 Subject: [PATCH 29/62] makefile fix for linux? --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 716d464..04d39d1 100644 --- a/Makefile +++ b/Makefile @@ -111,4 +111,8 @@ $(BUILDDIR)/$(TARGET)/script/builtin.o: $(BUILDDIR)/$(TARGET)/script/builtin.c $(BUILDDIR)/$(TARGET)/script/builtin.c: scripts/*.te @mkdir -p "$(@D)" +ifeq ($(OS),Windows_NT) @py te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" scripts +else + @python3 te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" scripts +endif From d2a0786875e61909d1b0782d34005425f2b8b070 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 26 Jul 2021 01:45:35 +0200 Subject: [PATCH 30/62] add save.commit() and save.write() --- bdk/libs/nx_savedata/save_data_file.c | 7 +-- scripts/FirmwareDump.te | 2 +- scripts/HelloWorld.te | 23 +++++--- source/script/saveClass.c | 82 ++++++++++++++++++++++++++- source/script/scriptError.c | 1 + source/script/standardLibrary.c | 2 +- 6 files changed, 102 insertions(+), 15 deletions(-) diff --git a/bdk/libs/nx_savedata/save_data_file.c b/bdk/libs/nx_savedata/save_data_file.c index edf85ba..7f3645d 100644 --- a/bdk/libs/nx_savedata/save_data_file.c +++ b/bdk/libs/nx_savedata/save_data_file.c @@ -99,10 +99,9 @@ bool save_data_file_write(save_data_file_ctx_t *ctx, uint64_t *out_bytes_written if (!save_data_file_validate_write_params(ctx, offset, count, ctx->mode, &is_resize_needed)) return false; - if (is_resize_needed) { - if (!save_data_file_set_size(ctx, offset + count)) - return false; - } + if (!save_data_file_set_size(ctx, offset + count)) + return false; + *out_bytes_written = save_allocation_table_storage_write(&ctx->base_storage, buffer, offset, count); return true; diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index e41e29c..7c20079 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -3,7 +3,7 @@ p=println pe={pause() exit()} fwstr={fw=maj.str()+"."+min.str()+"."+pat.str()} fv={a=readsave("bis:/save/8000000000000120") - b=a.readFile("/meta/imkvdb.arc") + b=a.read("/meta/imkvdb.arc") c=["BYTE[]",9,8,0,0,0,0,0,1] d=b.find(c) if(d>0){ diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te index d58366f..1d95158 100644 --- a/scripts/HelloWorld.te +++ b/scripts/HelloWorld.te @@ -5,13 +5,20 @@ a="Hello world!\n" a.print() -#i=0 -#while (i<10){ -# println(i) -# i=i+1 -#} -a = readdir("sd:/tegraexplorer") + +mountsys("SYSTEM") +s = readsave("sd:/8000000000000120") +f = s.read("/meta/imkvdb.arc") +println(f.len()) +println(f.slice(1,1).project()[0]) +s.write("/meta/imkvdb.arc", ["BYTE[]", 1,2]).print() +s.commit().print() + +#a = s.readdir("/") +pause() +exit() + println(a.result) println(a.files.len()) println(a.folders.len()) @@ -19,4 +26,6 @@ println(a.fileSizes.len()) a.files.foreach("b") { println(b) -} \ No newline at end of file +} + +pause() \ No newline at end of file diff --git a/source/script/saveClass.c b/source/script/saveClass.c index bcbc48b..eb7583a 100644 --- a/source/script/saveClass.c +++ b/source/script/saveClass.c @@ -1,14 +1,17 @@ #include "saveClass.h" #include "compat.h" +#include "intClass.h" +#include "dictionaryClass.h" u8 oneStringArgSave[] = {StringClass}; +u8 oneStrOneByteArrayArgSave[] = {StringClass, ByteArrayClass}; 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); @@ -21,8 +24,83 @@ ClassFunction(readFile){ return copyVariableToPtr(a); } +ClassFunction(writeFile){ + Variable_t *arg = (*args); + save_data_file_ctx_t dataArc; + if (!save_open_file(&caller->save->saveCtx, &dataArc, arg->string.value, OPEN_MODE_WRITE)) + return newIntVariablePtr(1); + + u64 outBytes = 0; + if (!save_data_file_write(&dataArc, &outBytes, 0, args[1]->solvedArray.vector.data, args[1]->solvedArray.vector.count)){ + return newIntVariablePtr(3); + }; + + if (outBytes != args[1]->solvedArray.vector.count){ + return newIntVariablePtr(4); + } + + return newIntVariablePtr(0); +} + +ClassFunction(getFiles){ + Variable_t* resPtr = newIntVariablePtr(0); + Variable_t ret = {.variableType = DictionaryClass, .dictionary.vector = newVec(sizeof(Dict_t), 4)}; + addVariableToDict(&ret, "result", resPtr); + + save_data_directory_ctx_t ctx; + if (!save_open_directory(&caller->save->saveCtx, &ctx, "/", OPEN_DIR_MODE_ALL)){ + resPtr->integer.value = 1; + return copyVariableToPtr(ret); + } + + u64 entryCount = 0; + if (!save_data_directory_get_entry_count(&ctx, &entryCount)){ + resPtr->integer.value = 2; + return copyVariableToPtr(ret); + } + + directory_entry_t* entries = malloc(sizeof(directory_entry_t) * entryCount); + u64 entryCountDirRead = 0; + if (!save_data_directory_read(&ctx, &entryCountDirRead, entries, entryCount)){ + resPtr->integer.value = 3; + + return copyVariableToPtr(ret); + } + + Variable_t fileNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; + Variable_t dirNamesArray = {.variableType = StringArrayClass, .solvedArray.vector = newVec(sizeof(char*), 0)}; + Variable_t fileSizeArray = {.variableType = IntArrayClass, .solvedArray.vector = newVec(sizeof(s64), 0)}; + + for (int i = 0; i < entryCountDirRead; i++){ + char *add = CpyStr(entries[i].name); + if (entries[i].type == DIR_ENT_TYPE_FILE){ + vecAdd(&fileNamesArray.solvedArray.vector, add); + s64 fileSize = entries[i].size; + vecAdd(&fileSizeArray.solvedArray.vector, fileSize); + } + else { + vecAdd(&dirNamesArray.solvedArray.vector, add); + } + } + + free(entries); + + addVariableToDict(&ret, "files", copyVariableToPtr(fileNamesArray)); + addVariableToDict(&ret, "folders", copyVariableToPtr(dirNamesArray)); + addVariableToDict(&ret, "fileSizes", copyVariableToPtr(fileSizeArray)); + + return copyVariableToPtr(ret); +} + +ClassFunction(saveClassCommit){ + return newIntVariablePtr(!save_commit(&caller->save->saveCtx)); +} + ClassFunctionTableEntry_t saveFunctions[] = { - {"readFile", readFile, 1, oneStringArgSave}, + {"read", readFile, 1, oneStringArgSave}, + {"write", writeFile, 2, oneStrOneByteArrayArgSave}, + //{"readdir", getFiles, 1, oneStringArgSave}, // Seems broken? + {"commit", saveClassCommit, 0, 0}, }; Variable_t getSaveMember(Variable_t* var, char* memberName) { diff --git a/source/script/scriptError.c b/source/script/scriptError.c index 0a2d957..8e218c9 100644 --- a/source/script/scriptError.c +++ b/source/script/scriptError.c @@ -14,4 +14,5 @@ void printScriptError(u8 errLevel, char* message, ...) { if (errLevel < SCRIPT_WARN) gfx_printf("\nError occured on or near line %d\n", (u32)scriptCurrentLine); va_end(args); + hidWait(); } \ No newline at end of file diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 7896202..c81d309 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -145,7 +145,7 @@ 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)) + if (f_open(&save->saveFile, arg->string.value, FA_READ | FA_WRITE)) return NULL; save_init(&save->saveCtx, &save->saveFile, dumpedKeys.save_mac_key, 0); if (!save_process(&save->saveCtx)) From 8807af9109d08e3e12b406278e074257e9c91513 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 26 Jul 2021 20:47:23 +0200 Subject: [PATCH 31/62] add #define SCRIPT_ONLY --- source/tegraexplorer/mainmenu.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index b9ec3f1..3a8641b 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -23,6 +23,7 @@ #include "../fs/menus/filemenu.h" #define INCLUDE_BUILTIN_SCRIPTS 1 +//#define SCRIPT_ONLY 1 #ifdef INCLUDE_BUILTIN_SCRIPTS #include "../../build/TegraExplorer/script/builtin.h" @@ -31,6 +32,7 @@ extern hekate_config h_cfg; enum { + #ifndef SCRIPT_ONLY MainExplore = 0, MainBrowseSd, MainMountSd, @@ -41,6 +43,9 @@ enum { MainViewKeys, MainViewCredits, MainExit, + #else + MainExit = 0, + #endif MainPowerOff, MainRebootRCM, MainRebootNormal, @@ -50,6 +55,7 @@ enum { }; MenuEntry_t mainMenuEntries[] = { + #ifndef SCRIPT_ONLY [MainExplore] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "-- Explore --"}, [MainBrowseSd] = {.optionUnion = COLORTORGB(COLOR_GREEN), .name = "Browse SD"}, [MainMountSd] = {.optionUnion = COLORTORGB(COLOR_YELLOW)}, // To mount/unmount the SD @@ -59,6 +65,7 @@ MenuEntry_t mainMenuEntries[] = { [MainPartitionSd] = {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "Partition the sd"}, [MainViewKeys] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "View dumped keys"}, [MainViewCredits] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "Credits"}, + #endif [MainExit] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "\n-- Exit --"}, [MainPowerOff] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Power off"}, [MainRebootRCM] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to RCM"}, @@ -148,17 +155,19 @@ void MountOrUnmountSD(){ } menuPaths mainMenuPaths[] = { + #ifndef SCRIPT_ONLY [MainBrowseSd] = HandleSD, [MainMountSd] = MountOrUnmountSD, [MainBrowseEmmc] = HandleEMMC, [MainBrowseEmummc] = HandleEMUMMC, [MainPartitionSd] = FormatSD, [MainViewKeys] = ViewKeys, + [MainViewCredits] = ViewCredits, + #endif [MainRebootAMS] = RebootToAMS, [MainRebootHekate] = RebootToHekate, [MainRebootRCM] = reboot_rcm, [MainPowerOff] = power_off, - [MainViewCredits] = ViewCredits, [MainRebootNormal] = reboot_normal, }; @@ -168,6 +177,7 @@ void EnterMainMenu(){ if (sd_get_card_removed()) sd_unmount(); + #ifndef SCRIPT_ONLY // -- Explore -- mainMenuEntries[MainBrowseSd].hide = !sd_mounted; mainMenuEntries[MainMountSd].name = (sd_mounted) ? "Unmount SD" : "Mount SD"; @@ -181,7 +191,7 @@ void EnterMainMenu(){ mainMenuEntries[MainRebootAMS].hide = (!sd_mounted || !FileExists("sd:/atmosphere/reboot_payload.bin")); mainMenuEntries[MainRebootHekate].hide = (!sd_mounted || !FileExists("sd:/bootloader/update.bin")); mainMenuEntries[MainRebootRCM].hide = h_cfg.t210b01; - + #endif // -- Scripts -- #ifndef INCLUDE_BUILTIN_SCRIPTS mainMenuEntries[MainScripts].hide = (!sd_mounted || !FileExists("sd:/tegraexplorer/scripts")); @@ -248,7 +258,6 @@ void EnterMainMenu(){ MenuEntry_t entry = entArray[res]; FSEntry_t fsEntry = {.name = entry.name, .sizeUnion = entry.sizeUnion}; RunScript("sd:/tegraexplorer/scripts", fsEntry); - hidWait(); #ifdef INCLUDE_BUILTIN_SCRIPTS } #endif From d4f95da062a683c5d7a0f6f5bc0357039a90889a Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 01:10:39 +0200 Subject: [PATCH 32/62] comments should count as lines --- source/script/parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/script/parser.c b/source/script/parser.c index e335762..f1207ab 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -127,6 +127,9 @@ u8 nextToken(char** inPtr, void** val) { while (*in && *in != '\n') in++; + + lineNumber++; + scriptCurrentLine = lineNumber; } else if (isValidWord(*in)) { char* startWord = in; From e9fb276e467ca686d6b9492ef7b8a2986aab88d1 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 00:01:46 +0100 Subject: [PATCH 33/62] automation is here automatically minifies scripts before embedding them gotta save them bytes --- Makefile | 7 +- ts-minifier.py | 181 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 ts-minifier.py diff --git a/Makefile b/Makefile index 04d39d1..2cad851 100644 --- a/Makefile +++ b/Makefile @@ -111,8 +111,11 @@ $(BUILDDIR)/$(TARGET)/script/builtin.o: $(BUILDDIR)/$(TARGET)/script/builtin.c $(BUILDDIR)/$(TARGET)/script/builtin.c: scripts/*.te @mkdir -p "$(@D)" + @mkdir -p "$(BUILDDIR)/$(TARGET)/scripts" ifeq ($(OS),Windows_NT) - @py te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" scripts + @py ts-minifier.py --no-replace-functions -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) + @py te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" "$(BUILDDIR)/$(TARGET)/scripts" else - @python3 te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" scripts + @python3 ts-minifier.py --no-replace-functions -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) + @python3 te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" "$(BUILDDIR)/$(TARGET)/scripts" endif diff --git a/ts-minifier.py b/ts-minifier.py new file mode 100644 index 0000000..6c8dfcc --- /dev/null +++ b/ts-minifier.py @@ -0,0 +1,181 @@ +# Copyright (c) 2021 bleck9999 +# https://github.com/bleck9999/ts-minifier +# Version: 92743efc + +import argparse +import re + +# if is not included because it's already 2 characters +sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'mountemu': "_e", 'readsave': "_r", + 'exit': "_q", 'break': "_b", 'dict': "_d", 'setpixel': "_y", 'readdir': "_i", 'copyfile': "_c", + 'mkdir': "_k", 'memory': "_m", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", + 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", + "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_"} +replace_functions = True + + +def wantsumspace(s: str): + for c in s.lower(): + if (ord(c) < 97 or ord(c) > 122) and (ord(c) != 95) and not (c.isnumeric()): + return False + return True + + +def commentstartswhere(s: str): + quoted = False + for c in range(len(s)): + if s[c] == '"': + quoted = not quoted + if s[c] == '#' and not quoted: + return c + return None + + +def minify(script: str): + # currently ts does not seem to allow 's to mark a quote + # (https://github.com/suchmememanyskill/TegraExplorer/blob/tsv3/source/script/parser.c#L173) + # im fine with that, it makes doing this a lot easier + # strings = script.split(sep='"') + str_reuse = {} + requires = "" + mcode = "" + stl_counts = {}.fromkeys(sub_funcs, 0) + # while part < len(strings): + for line in script.split(sep='\n'): + # maybe in future it'll shrink user defined names + # dont hold out hope for that because `a.files.foreach("b") {println(b)}` is valid syntax + # and i dont have the skill or patience to deal with that + + # # in theory all the even numbered indexes should be outside quotes, so we ignore any parts with an odd index + # if part % 2 == 1: + # if strings[part] not in str_reuse: + # str_reuse[strings[part]] = 0 + # else: + # str_reuse[strings[part]] += 1 + # mcode += f'"{strings[part]}"' + start = commentstartswhere(line) + if start is None: + start = -1 + + if "REQUIRE " in line[start:]: + requires += line[start:] + '\n' # leave REQUIREs unmodified + # comments are terminated by a newline so we need to add one back in + + # *deep breath* + # slicing is exclusive on the right side of the colon so the "no comment" value of start=-1 would cut off + # the last character of the line which would lead to several issues + # however this is desirable when there *is* a comment, since it being exclusive means there isn't a trailing # + # and if you're wondering about the above check that uses line[start:] this doesn't matter, + # one character cant contain an 8 character substring + if start != -1: + line = line[:start] + line = line.split(sep='"') + + if len(line) % 2 == 0: + print("You appear to have string literals spanning multiple lines. Please seek professional help") + raise Exception("Too much hatred") + part = 0 + while part < len(line): + # all the odd numbered indexes should be inside quotes + if part % 2 == 0: + if not line[part]: + break + for s in sub_funcs: + stl_counts[s] += len(re.findall("(? len(func)+3) so dont even try + if stl_counts[func] >= 2: + savings = stl_counts[func] * (len(func) - 2) - (len(func) + 3) + print(f"Replacing all {stl_counts[func]} usages of {func} would save {savings}byte{'s' if savings != 1 else ''}") + if (savings < 0) or not replace_functions: + print("Savings negative or automatic replacement disabled, continuing") + continue + func_min = sub_funcs[func] # now here we have to assume nobody is using any of our substitute vars + # should be a pretty safe assumption but knowing for sure would require about the same amount of effort + # as it would to replace all user defined variables + ucode = "" # this is rather hacky + sections = [0] + for m in re.finditer(r"(?= 2: + # we can't auto replace strings without a full parser + # unlike with the stdlib functions we cant make a lookup table ahead of time + # and generating shorter names on the fly sounds like an absolute nightmare no thanks + print(f'Warning: string "{string}" of len {len(string)} reused {count} times') + + return requires + mmcode.strip() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Minify tsv3 scripts, useful for embedding", + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("source", type=str, nargs='+', help="source files to minify") + parser.add_argument("-d", type=str, nargs='?', help="destination folder for minified scripts" + "\ndefault: ./", default='./') + parser.add_argument("--replace-functions", action=argparse.BooleanOptionalAction, + help="if false, warn if functions are reused instead of replacing them\ndefault: true") + + args = parser.parse_args() + files = args.source + dest = args.d[:-1] if args.d[-1] == '/' else args.d + replace_functions = args.replace_functions if args.replace_functions is not None else True + + for file in files: + print(f"Minifying {file}") + with open(file, 'r') as f: + r = minify(f.read()) + file = file.split(sep='.')[0].split(sep='/')[-1] + f = open(f"{dest}/{file}_min.te", 'w') + f.write(r) + From b40258f2941e812e15aa1d46c10424db19d16b85 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 13:08:29 +0200 Subject: [PATCH 34/62] time to change the workflow file again and break everything --- .github/workflows/builder.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index b168d8c..019235f 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -14,7 +14,11 @@ jobs: run: | sudo apt update -y sudo apt install build-essential -y - alias py=python3 + + sudo apt install python3.9 -y + sudo rm /usr/bin/python3 + sudo ln -s python3.9 /usr/bin/python3 + make -j$(nproc) - uses: actions/upload-artifact@master From 1a533d95af671472a3d1ada5b37df2e56e8ae4af Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 13:16:15 +0200 Subject: [PATCH 35/62] workflow file try 2 --- .github/workflows/builder.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index 019235f..c9e2ace 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -15,6 +15,8 @@ jobs: sudo apt update -y sudo apt install build-essential -y + sudo apt install software-properties-common -y + sudo add-apt-repository ppa:deadsnakes/ppa -y sudo apt install python3.9 -y sudo rm /usr/bin/python3 sudo ln -s python3.9 /usr/bin/python3 From b8496cb935d6cfaf187b853b901e0a9a9310d5a6 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 13:21:52 +0200 Subject: [PATCH 36/62] workflow file try 3 --- .github/workflows/builder.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index c9e2ace..42df8a3 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -17,6 +17,7 @@ jobs: sudo apt install software-properties-common -y sudo add-apt-repository ppa:deadsnakes/ppa -y + sudo apt update -y sudo apt install python3.9 -y sudo rm /usr/bin/python3 sudo ln -s python3.9 /usr/bin/python3 From 4b5b8e80a28a6aebebabee5dddc1840791d525b6 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 13:34:56 +0200 Subject: [PATCH 37/62] guess we're staying on py3.8 --- .github/workflows/builder.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index 42df8a3..b71ccbb 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -14,14 +14,7 @@ jobs: run: | sudo apt update -y sudo apt install build-essential -y - - sudo apt install software-properties-common -y - sudo add-apt-repository ppa:deadsnakes/ppa -y - sudo apt update -y - sudo apt install python3.9 -y - sudo rm /usr/bin/python3 - sudo ln -s python3.9 /usr/bin/python3 - + make -j$(nproc) - uses: actions/upload-artifact@master From fd7ebd1cefda5890537b9a8af1a8d77d8ab6a7a6 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 12:40:37 +0100 Subject: [PATCH 38/62] compatibility tm --- ts-minifier.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index 6c8dfcc..a7a5c2f 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: 92743efc +# Version: fc30eb39 import argparse import re @@ -11,7 +11,7 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'mkdir': "_k", 'memory': "_m", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_"} -replace_functions = True +replace_functions = False def wantsumspace(s: str): @@ -163,13 +163,13 @@ if __name__ == '__main__': parser.add_argument("source", type=str, nargs='+', help="source files to minify") parser.add_argument("-d", type=str, nargs='?', help="destination folder for minified scripts" "\ndefault: ./", default='./') - parser.add_argument("--replace-functions", action=argparse.BooleanOptionalAction, - help="if false, warn if functions are reused instead of replacing them\ndefault: true") + parser.add_argument("--replace-functions", action="store_true", default=False, + help="automatically replace reused functions instead of just warning\ndefault: false") args = parser.parse_args() files = args.source dest = args.d[:-1] if args.d[-1] == '/' else args.d - replace_functions = args.replace_functions if args.replace_functions is not None else True + replace_functions = args.replace_functions if args.replace_functions is not None else False for file in files: print(f"Minifying {file}") @@ -178,4 +178,3 @@ if __name__ == '__main__': file = file.split(sep='.')[0].split(sep='/')[-1] f = open(f"{dest}/{file}_min.te", 'w') f.write(r) - From 058853d7d2131acedb40ce6ca9a6bc768bbd2776 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 12:42:34 +0100 Subject: [PATCH 39/62] fukin oops --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2cad851..2ea2712 100644 --- a/Makefile +++ b/Makefile @@ -113,9 +113,9 @@ $(BUILDDIR)/$(TARGET)/script/builtin.c: scripts/*.te @mkdir -p "$(@D)" @mkdir -p "$(BUILDDIR)/$(TARGET)/scripts" ifeq ($(OS),Windows_NT) - @py ts-minifier.py --no-replace-functions -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) + @py ts-minifier.py -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) @py te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" "$(BUILDDIR)/$(TARGET)/scripts" else - @python3 ts-minifier.py --no-replace-functions -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) + @python3 ts-minifier.py -d "$(BUILDDIR)/$(TARGET)/scripts" $(wildcard scripts/*.te) @python3 te2c.py "$(BUILDDIR)/$(TARGET)/script/builtin" "$(BUILDDIR)/$(TARGET)/scripts" endif From fb3951435f83eb39e6cecb93569c2f84da804c84 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 14:16:01 +0200 Subject: [PATCH 40/62] add setpixels, printpos --- scripts/HelloWorld.te | 12 +++++------- source/script/standardLibrary.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te index 1d95158..9be5fc1 100644 --- a/scripts/HelloWorld.te +++ b/scripts/HelloWorld.te @@ -7,13 +7,9 @@ a.print() -mountsys("SYSTEM") -s = readsave("sd:/8000000000000120") -f = s.read("/meta/imkvdb.arc") -println(f.len()) -println(f.slice(1,1).project()[0]) -s.write("/meta/imkvdb.arc", ["BYTE[]", 1,2]).print() -s.commit().print() +printpos(20, 30) +setpixels(0, 0, 1279, 100, 0xFF0000) +println("sup") #a = s.readdir("/") pause() @@ -24,6 +20,8 @@ println(a.files.len()) println(a.folders.len()) println(a.fileSizes.len()) + + a.files.foreach("b") { println(b) } diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index c81d309..de0dde1 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -162,6 +162,18 @@ ClassFunction(stdSetPixel) { return &emptyClass; } +ClassFunction(stdSetPixels){ + gfx_box(getIntValue(args[0]), getIntValue(args[1]), getIntValue(args[2]), getIntValue(args[3]), (u32)getIntValue(args[4])); + return &emptyClass; +} + +ClassFunction(stdSetPrintPos){ + if (getIntValue(args[0]) > 0 && getIntValue(args[1]) > 0){ + gfx_con_setpos((getIntValue(args[0]) % 78) * 16, (getIntValue(args[1]) % 42) * 16); + } + return &emptyClass; +} + // Takes [str]. Returns empty. str: path to dir ClassFunction(stdReadDir){ Variable_t* resPtr = newIntVariablePtr(0); @@ -441,7 +453,7 @@ STUBBED(stdFileRead) u8 oneIntoneFunction[] = { IntClass, FunctionClass }; u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; u8 oneStringArgStd[] = {StringClass}; -u8 threeIntsStd[] = { IntClass, IntClass, IntClass }; +u8 threeIntsStd[] = { IntClass, IntClass, IntClass, IntClass, IntClass }; u8 twoStringArgStd[] = {StringClass, StringClass}; u8 oneIntStd[] = {IntClass}; u8 menuArgsStd[] = {StringArrayClass, IntClass, IntArrayClass}; @@ -461,7 +473,9 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { // Utils {"print", stdPrint, VARARGCOUNT, 0}, {"println", stdPrintLn, VARARGCOUNT, 0}, - {"setpixel", stdSetPixel, 3, threeIntsStd}, // TODO: change for setblock + {"printpos", stdSetPrintPos, 2, threeIntsStd}, + {"setpixel", stdSetPixel, 3, threeIntsStd}, + {"setpixels", stdSetPixels, 5, threeIntsStd}, {"emu", stdHasEmu, 0, 0}, {"clear", stdClear, 0, 0}, {"timer", stdGetMs, 0, 0}, From f5a4eec6bb2db806a91af785b420f941057ed173 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 17:42:34 +0200 Subject: [PATCH 41/62] add emmcFile functions --- scripts/HelloWorld.te | 2 ++ source/script/standardLibrary.c | 61 +++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te index 9be5fc1..451375f 100644 --- a/scripts/HelloWorld.te +++ b/scripts/HelloWorld.te @@ -5,7 +5,9 @@ a="Hello world!\n" a.print() +if (emmcread("sd:/prodinfo_temp_dump.bin", "PRODINFO")){ print("fuk") pause() exit() } +if (emmcwrite("sd:/prodinfo_temp_dump.bin", "PRODINFO")) { print("fuk2") pause exit() } printpos(20, 30) setpixels(0, 0, 1279, 100, 0xFF0000) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index de0dde1..71fdabe 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -24,6 +24,7 @@ #include #include "../fs/fsutils.h" #include +#include "../storage/emmcfile.h" #endif // Takes [int, function]. Returns elseable. ClassFunction(stdIf) { @@ -399,6 +400,34 @@ ClassFunction(stdLaunchPayload){ return newIntVariablePtr(launch_payload(args[0]->string.value)); } +int emmcFile(char *sdFile, char *sysPart, u8 mmc, u8 write){ + + if (!emu_cfg.enabled && mmc == MMC_CONN_EMUMMC){ + return 1; + } + + if (connectMMC(mmc)) + return 1; + + return DumpOrWriteEmmcPart(sdFile, sysPart, write, 1).err; +} + +ClassFunction(stdEmmcFileRead){ + return newIntVariablePtr(emmcFile(args[0]->string.value, args[1]->string.value, MMC_CONN_EMMC, 0)); +} + +ClassFunction(stdEmmcFileWrite){ + return newIntVariablePtr(emmcFile(args[0]->string.value, args[1]->string.value, MMC_CONN_EMMC, 1)); +} + +ClassFunction(stdEmummcFileRead){ + return newIntVariablePtr(emmcFile(args[0]->string.value, args[1]->string.value, MMC_CONN_EMUMMC, 0)); +} + +ClassFunction(stdEmummcFileWrite){ + return newIntVariablePtr(emmcFile(args[0]->string.value, args[1]->string.value, MMC_CONN_EMUMMC, 1)); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -452,10 +481,8 @@ STUBBED(stdFileRead) u8 oneIntoneFunction[] = { IntClass, FunctionClass }; u8 doubleFunctionClass[] = { FunctionClass, FunctionClass }; -u8 oneStringArgStd[] = {StringClass}; u8 threeIntsStd[] = { IntClass, IntClass, IntClass, IntClass, IntClass }; u8 twoStringArgStd[] = {StringClass, StringClass}; -u8 oneIntStd[] = {IntClass}; u8 menuArgsStd[] = {StringArrayClass, IntClass, IntArrayClass}; u8 oneStringOneByteArrayStd[] = {StringClass, ByteArrayClass}; @@ -467,7 +494,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"break", stdBreak, 0, 0}, // Class creation - {"readsave", stdMountSave, 1, oneStringArgStd}, + {"readsave", stdMountSave, 1, twoStringArgStd}, {"dict", stdDict, 0, 0}, // Utils @@ -480,34 +507,38 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"clear", stdClear, 0, 0}, {"timer", stdGetMs, 0, 0}, {"memory", stdGetMemUsage, 0, 0}, - {"pause", stdPauseMask, 1, oneIntStd}, + {"pause", stdPauseMask, 1, threeIntsStd}, {"pause", stdPause, 0, 0}, - {"color", stdColor, 1, oneIntStd}, + {"color", stdColor, 1, threeIntsStd}, {"menu", stdMenuFull, 3, menuArgsStd}, {"menu", stdMenuFull, 2, menuArgsStd}, // System - {"mountsys", stdMountSysmmc, 1, oneStringArgStd}, - {"mountemu", stdMountEmummc, 1, oneStringArgStd}, - {"ncatype", stdGetNcaType, 1, oneStringArgStd}, + {"mountsys", stdMountSysmmc, 1, twoStringArgStd}, + {"mountemu", stdMountEmummc, 1, twoStringArgStd}, + {"ncatype", stdGetNcaType, 1, twoStringArgStd}, + {"emmcread", stdEmmcFileRead, 2, twoStringArgStd}, + {"emmcwrite", stdEmmcFileWrite, 2, twoStringArgStd}, + {"emummcread", stdEmummcFileRead, 2, twoStringArgStd}, + {"emummcwrite", stdEmummcFileWrite, 2, twoStringArgStd}, // FileSystem // Dir - {"readdir", stdReadDir, 1, oneStringArgStd}, - {"deldir", stdRmDir, 1, oneStringArgStd}, - {"mkdir", stdMkdir, 1, oneStringArgStd}, + {"readdir", stdReadDir, 1, twoStringArgStd}, + {"deldir", stdRmDir, 1, twoStringArgStd}, + {"mkdir", stdMkdir, 1, twoStringArgStd}, {"copydir", stdCopyDir, 2, twoStringArgStd}, // File {"copyfile", stdFileCopy, 2, twoStringArgStd}, {"movefile", stdFileMove, 2, twoStringArgStd}, - {"delfile", stdFileDel, 1, oneStringArgStd}, - {"readfile", stdFileRead, 1, oneStringArgStd}, + {"delfile", stdFileDel, 1, twoStringArgStd}, + {"readfile", stdFileRead, 1, twoStringArgStd}, {"writefile", stdFileWrite, 2, oneStringOneByteArrayStd}, // Utils - {"fsexists", stdFileExists, 1, oneStringArgStd}, - {"payload", stdLaunchPayload, 1, oneStringArgStd}, + {"fsexists", stdFileExists, 1, twoStringArgStd}, + {"payload", stdLaunchPayload, 1, twoStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { From e42cc4c8ebe9eee83cd5f70965a032227643496e Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 17:43:47 +0200 Subject: [PATCH 42/62] delete old scripts --- scripts/ButtonTest.te | 17 ----------------- scripts/HelloWorld.te | 31 ------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 scripts/ButtonTest.te delete mode 100644 scripts/HelloWorld.te diff --git a/scripts/ButtonTest.te b/scripts/ButtonTest.te deleted file mode 100644 index ff03605..0000000 --- a/scripts/ButtonTest.te +++ /dev/null @@ -1,17 +0,0 @@ -println("Testing pause") -x = pause() -println(x.raw, " ", x.a, "", x.power) -println("Testing masked pause") -x = pause(1 << 3) -println(x.raw, " ", x.a) -color(0xFF0000) -println("This text should be red!") -color(0x00FF00) -println("and this green!") - -COLOR_RED = 0xFF0000 -COLOR_BLUE = 0x0000FF - -menu(["a", "b", "c"], 1, [COLOR_BLUE, COLOR_RED | 0x1000000, COLOR_BLUE]).print() - -exit() \ No newline at end of file diff --git a/scripts/HelloWorld.te b/scripts/HelloWorld.te deleted file mode 100644 index 451375f..0000000 --- a/scripts/HelloWorld.te +++ /dev/null @@ -1,31 +0,0 @@ -#REQUIRE VER 3.0.6 -#REQUIRE MINERVA -#REQUIRE KEYS - -a="Hello world!\n" -a.print() - -if (emmcread("sd:/prodinfo_temp_dump.bin", "PRODINFO")){ print("fuk") pause() exit() } - -if (emmcwrite("sd:/prodinfo_temp_dump.bin", "PRODINFO")) { print("fuk2") pause exit() } - -printpos(20, 30) -setpixels(0, 0, 1279, 100, 0xFF0000) -println("sup") - -#a = s.readdir("/") -pause() -exit() - -println(a.result) -println(a.files.len()) -println(a.folders.len()) -println(a.fileSizes.len()) - - - -a.files.foreach("b") { - println(b) -} - -pause() \ No newline at end of file From 0a007bf3c3a5d74b566d84e0f8279aa40d82d96f Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 18:37:22 +0100 Subject: [PATCH 43/62] new functions go brr --- ts-minifier.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index a7a5c2f..b43baf0 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: fc30eb39 +# Version: 4fc47b37 import argparse import re @@ -10,7 +10,8 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'exit': "_q", 'break': "_b", 'dict': "_d", 'setpixel': "_y", 'readdir': "_i", 'copyfile': "_c", 'mkdir': "_k", 'memory': "_m", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", - "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_"} + "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", + "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_"} replace_functions = False From beb6b1ec336592229261c04249263f36585a11af Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 20:36:30 +0200 Subject: [PATCH 44/62] add esc/combine path --- source/script/standardLibrary.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 71fdabe..4858424 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -8,6 +8,7 @@ #include "scriptError.h" #include #include "dictionaryClass.h" +#include "StringClass.h" #ifndef WIN32 #include "../storage/mountmanager.h" @@ -428,6 +429,30 @@ ClassFunction(stdEmummcFileWrite){ return newIntVariablePtr(emmcFile(args[0]->string.value, args[1]->string.value, MMC_CONN_EMUMMC, 1)); } +ClassFunction(stdCombinePaths){ + if (argsLen < 2 || args[0]->variableType != StringClass){ + SCRIPT_FATAL_ERR("stdCombinePaths needs 2+ args"); + } + + char *res = CpyStr(args[0]->string.value); + + for (int i = 1; i < argsLen; i++){ + if (args[i]->variableType != StringClass){ + SCRIPT_FATAL_ERR("stdCombinePaths needs 2+ args"); + } + + char *temp = CombinePaths(res, args[i]->string.value); + free(res); + res = temp; + } + + return newStringVariablePtr(res, 0, 1); +} + +ClassFunction(stdEscPaths){ + return newStringVariablePtr(EscapeFolder(args[0]->string.value), 0, 1); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -539,6 +564,8 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { // Utils {"fsexists", stdFileExists, 1, twoStringArgStd}, {"payload", stdLaunchPayload, 1, twoStringArgStd}, + {"combinepath", stdCombinePaths, VARARGCOUNT, 0}, + {"escapepath", stdEscPaths, 1, twoStringArgStd}, }; ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { From d68912f5e59d251204a5ad8394059c6683e9dbc8 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 19:46:48 +0100 Subject: [PATCH 45/62] crab _min is gone crab (also stdlib updates) --- ts-minifier.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index b43baf0..b8a6208 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: 4fc47b37 +# Version: b9ea46f3 import argparse import re @@ -11,7 +11,8 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'mkdir': "_k", 'memory': "_m", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", - "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_"} + "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_", "escapepath": "x_", + "combinepath": "a_"} replace_functions = False @@ -177,5 +178,8 @@ if __name__ == '__main__': with open(file, 'r') as f: r = minify(f.read()) file = file.split(sep='.')[0].split(sep='/')[-1] - f = open(f"{dest}/{file}_min.te", 'w') + if dest != '.': + f = open(f"{dest}/{file}.te", 'w') + else: + f = open(f"{dest}/{file}_min.te", 'w') f.write(r) From 205e0510d14ff5051e39dc92a6e74fd3084d0677 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 19:56:53 +0100 Subject: [PATCH 46/62] speed --- ts-minifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index b8a6208..9088fa2 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: b9ea46f3 +# Version: 0793d0a7 import argparse import re @@ -12,7 +12,7 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_", "escapepath": "x_", - "combinepath": "a_"} + "combinepath": "a_", "cwd": "d_"} replace_functions = False From 797a5f95b5553363cdd29be77215278548bd7201 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 21:05:32 +0200 Subject: [PATCH 47/62] remove memory(), add cwd(), #REQUIRE SD --- scripts/FirmwareDump.te | 1 + source/fs/menus/filemenu.c | 18 ++++-------------- source/script/parser.c | 12 ++++++++++++ source/script/standardLibrary.c | 6 +++++- source/tegraexplorer/mainmenu.c | 5 ----- source/tegraexplorer/tconf.h | 1 + 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/scripts/FirmwareDump.te b/scripts/FirmwareDump.te index 7c20079..d01d5c8 100644 --- a/scripts/FirmwareDump.te +++ b/scripts/FirmwareDump.te @@ -1,4 +1,5 @@ #REQUIRE KEYS +#REQUIRE SD p=println pe={pause() exit()} fwstr={fw=maj.str()+"."+min.str()+"."+pat.str()} diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index c46e376..046f059 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -73,6 +73,7 @@ void DeleteFile(char *path, FSEntry_t entry){ } void RunScriptString(char *str, u32 size){ + TConf.scriptCWD = "sd:/"; gfx_clearscreen(); ParserRet_t ret = parseScript(str, size); setStaticVars(&ret.staticVarHolder); @@ -89,7 +90,8 @@ void RunScript(char *path, FSEntry_t entry){ char *thing = CombinePaths(path, entry.name); u32 size; char *script = sd_file_read(thing, &size); - free(thing); + TConf.scriptCWD = thing; + if (!script) return; @@ -97,19 +99,6 @@ void RunScript(char *path, FSEntry_t entry){ return; gfx_clearscreen(); - /* - scriptCtx_t ctx = createScriptCtx(); - ctx.script = runLexer(script, size); - free(script); - - dictVectorAdd(&ctx.varDict, newDict(CpyStr("_CWD"), (newVar(StringType, 0, .stringType = path)))); - dictVectorAdd(&ctx.varDict, newDict(CpyStr("_EMU"), (newVar(IntType, 0, emu_cfg.enabled)))); - - printError(mainLoop(&ctx)); - - freeDictVector(&ctx.varDict); - lexarVectorClear(&ctx.script); - */ ParserRet_t ret = parseScript(script, size); free(script); @@ -121,6 +110,7 @@ void RunScript(char *path, FSEntry_t entry){ exitFunction(ret.main.operations.data, ret.main.operations.count); vecFree(ret.staticVarHolder); vecFree(ret.main.operations); + free(thing); } void RenameFile(char *path, FSEntry_t entry){ diff --git a/source/script/parser.c b/source/script/parser.c index f1207ab..3b2ed8b 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -15,6 +15,7 @@ #ifndef WIN32 #include "../tegraexplorer/tconf.h" +#include #endif static inline int isValidWord(char c) { @@ -123,6 +124,17 @@ u8 nextToken(char** inPtr, void** val) { return Token_Fatal_Err; } } + else if (!memcmp(in + 9, "SD", 2)) { + #ifdef WIN32 + u8 gotSd = 0; + #else + u8 gotSd = sd_mount(); + #endif + if (!gotSd){ + printScriptError(SCRIPT_LEXER_FATAL, "Sd required."); + return Token_Fatal_Err; + } + } } while (*in && *in != '\n') diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 4858424..f3d82d9 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -453,6 +453,10 @@ ClassFunction(stdEscPaths){ return newStringVariablePtr(EscapeFolder(args[0]->string.value), 0, 1); } +ClassFunction(stdGetCwd){ + return newStringVariablePtr(CpyStr(TConf.scriptCWD), 0, 1); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -529,9 +533,9 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"setpixel", stdSetPixel, 3, threeIntsStd}, {"setpixels", stdSetPixels, 5, threeIntsStd}, {"emu", stdHasEmu, 0, 0}, + {"cwd", stdGetCwd, 0, 0}, {"clear", stdClear, 0, 0}, {"timer", stdGetMs, 0, 0}, - {"memory", stdGetMemUsage, 0, 0}, {"pause", stdPauseMask, 1, threeIntsStd}, {"pause", stdPause, 0, 0}, {"color", stdColor, 1, threeIntsStd}, diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 3a8641b..f94aadf 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -126,11 +126,6 @@ void ViewCredits(){ if (hidRead()->r) gfx_printf("%k\"I'm not even sure if it works\" - meme", COLOR_ORANGE); - heap_monitor_t a = {0}; - heap_monitor(&a, false); - gfx_printf("\nUsed: %d\nTotal: %d\n", a.used, a.total); - - hidWait(); } diff --git a/source/tegraexplorer/tconf.h b/source/tegraexplorer/tconf.h index 33f1237..0e0ea3b 100644 --- a/source/tegraexplorer/tconf.h +++ b/source/tegraexplorer/tconf.h @@ -34,6 +34,7 @@ typedef struct { }; const char *pkg1ID; u8 pkg1ver; + char *scriptCWD; } TConf_t; extern TConf_t TConf; From 39d2ef3e8a9f4b0a68b0ca3789f8440f08426353 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 20:07:36 +0100 Subject: [PATCH 48/62] im forgetting things --- ts-minifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index 9088fa2..986953b 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: 0793d0a7 +# Version: 360e126a import argparse import re @@ -8,7 +8,7 @@ import re # if is not included because it's already 2 characters sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'mountemu': "_e", 'readsave': "_r", 'exit': "_q", 'break': "_b", 'dict': "_d", 'setpixel': "_y", 'readdir': "_i", 'copyfile': "_c", - 'mkdir': "_k", 'memory': "_m", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", + 'mkdir': "_k", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_", "escapepath": "x_", From 094d43916c75e3d977267502128a126d7e52f7bb Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 21:43:11 +0200 Subject: [PATCH 49/62] oops --- source/script/standardLibrary.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index f3d82d9..a6eb608 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -340,8 +340,7 @@ ClassFunction(stdMenuFull){ u32 x=0,y=0; gfx_con_getpos(&x,&y); - - int res = newMenu(&v, getIntValue(args[1]), ScreenDefaultLenX - ((x + 1) / 16), ScreenDefaultLenY - ((y + 1) / 16) - 1, ENABLEB | ALWAYSREDRAW, 0); + int res = newMenu(&v, getIntValue(args[1]), ScreenDefaultLenX - ((x + 1) / 16), 40 - ((y + 1) / 16) - 1, ENABLEB | ALWAYSREDRAW, 0); vecFree(v); return newIntVariablePtr(res); } From 192568b686fa67d1d9d7d2388d9cd984a052f770 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Tue, 27 Jul 2021 22:00:18 +0200 Subject: [PATCH 50/62] re-implement tsv2 bug --- source/script/genericClass.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 08053c6..2cf0799 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -112,11 +112,8 @@ Variable_t* genericCall(Variable_t* var, CallArgs_t* ref) { if (var->variableType != FunctionClass){ SCRIPT_FATAL_ERR("Call on non function class"); } - + Function_t* f = ref->extra; if (var->function.builtIn) { - // TODO: implement arg handling - - Function_t* f = ref->extra; if (f->operations.count == 0) { return genericCallDirect(var, NULL, 0); } @@ -184,10 +181,14 @@ Variable_t* genericCall(Variable_t* var, CallArgs_t* ref) { } } else { - Variable_t *ret = eval(var->function.function.operations.data, var->function.function.operations.count, 1); - if (ret == NULL) + if (f->operations.count){ + if (eval(f->operations.data, f->operations.count, 0) == NULL) + return NULL; + } + + if (eval(var->function.function.operations.data, var->function.function.operations.count, 0) == NULL) return NULL; - removePendingReference(ret); + return &emptyClass; } } From 74b6106f263af78465590646b09790495df50d9a Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Wed, 28 Jul 2021 00:31:36 +0200 Subject: [PATCH 51/62] add power() --- source/script/standardLibrary.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index a6eb608..6ce7421 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -456,6 +456,11 @@ ClassFunction(stdGetCwd){ return newStringVariablePtr(CpyStr(TConf.scriptCWD), 0, 1); } +ClassFunction(stdPower){ + power_set_state(MIN(0, (getIntValue(args[0]) % POWER_OFF_REBOOT))); + return &emptyClass; +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -540,6 +545,7 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"color", stdColor, 1, threeIntsStd}, {"menu", stdMenuFull, 3, menuArgsStd}, {"menu", stdMenuFull, 2, menuArgsStd}, + {"power", stdPower, 1, threeIntsStd}, // System {"mountsys", stdMountSysmmc, 1, twoStringArgStd}, From 6a54e31d8e1ac8aa292e20cd627ae212be73639a Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Tue, 27 Jul 2021 23:34:33 +0100 Subject: [PATCH 52/62] more power --- ts-minifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index 986953b..aefa81d 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: 360e126a +# Version: 85700fdd import argparse import re @@ -12,7 +12,7 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_", "escapepath": "x_", - "combinepath": "a_", "cwd": "d_"} + "combinepath": "a_", "cwd": "d_", "power": "o_"} replace_functions = False From 87fb74060291eee419f175e1cdd45bf35b324c0c Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Wed, 28 Jul 2021 00:46:39 +0200 Subject: [PATCH 53/62] regain vs compatibility --- source/script/genericClass.c | 4 +-- source/script/scriptError.c | 4 ++- source/script/standardLibrary.c | 48 +++++++++++++-------------------- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/source/script/genericClass.c b/source/script/genericClass.c index 2cf0799..6113f8a 100644 --- a/source/script/genericClass.c +++ b/source/script/genericClass.c @@ -43,8 +43,8 @@ Variable_t* genericGet(Variable_t* var, CallArgs_t* ref) { 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; + if (member.variableType == None) + break; if (member.variableType == ReferenceType) { return member.referenceType; diff --git a/source/script/scriptError.c b/source/script/scriptError.c index 8e218c9..7feef5b 100644 --- a/source/script/scriptError.c +++ b/source/script/scriptError.c @@ -14,5 +14,7 @@ void printScriptError(u8 errLevel, char* message, ...) { if (errLevel < SCRIPT_WARN) gfx_printf("\nError occured on or near line %d\n", (u32)scriptCurrentLine); va_end(args); - hidWait(); + #ifndef WIN32 + hidWait(); + #endif } \ No newline at end of file diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 6ce7421..0f1816a 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -464,36 +464,14 @@ ClassFunction(stdPower){ #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } -ClassFunction(stdMountSysmmc){ - return newIntVariablePtr(0); -} -ClassFunction(stdMountSave){ - return newIntVariablePtr(0); -} -ClassFunction(stdSetPixel) { - return newIntVariablePtr(0); -} - -ClassFunction(stdReadDir){ - return newIntVariablePtr(0); -} - -ClassFunction(stdFileCopy){ - return newIntVariablePtr(0); -} - -ClassFunction(stdMkdir){ - return newIntVariablePtr(0); -} - -ClassFunction(stdGetMemUsage) { - return newIntVariablePtr(0); -} - -ClassFunction(stdGetNcaType) { - return newIntVariablePtr(0); -} - +STUBBED(stdMountSysmmc) +STUBBED(stdMountSave) +STUBBED(stdSetPixel) +STUBBED(stdReadDir) +STUBBED(stdFileCopy) +STUBBED(stdMkdir) +STUBBED(stdGetMemUsage) +STUBBED(stdGetNcaType) STUBBED(stdPause) STUBBED(stdPauseMask) STUBBED(stdColor) @@ -510,6 +488,16 @@ STUBBED(stdFileMove) STUBBED(stdLaunchPayload) STUBBED(stdFileWrite) STUBBED(stdFileRead) +STUBBED(stdCombinePaths) +STUBBED(stdEmmcFileWrite) +STUBBED(stdEmmcFileRead) +STUBBED(stdEmummcFileRead) +STUBBED(stdEmummcFileWrite) +STUBBED(stdEscPaths) +STUBBED(stdGetCwd) +STUBBED(stdPower) +STUBBED(stdSetPrintPos) +STUBBED(stdSetPixels) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass }; From 425f3e82b162d7d079756c98f134d7d0d906555c Mon Sep 17 00:00:00 2001 From: suchmememanyskill <38142618+suchmememanyskill@users.noreply.github.com> Date: Wed, 28 Jul 2021 11:30:14 +0200 Subject: [PATCH 54/62] I'm stupid --- source/script/standardLibrary.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 0f1816a..27efb02 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -457,7 +457,7 @@ ClassFunction(stdGetCwd){ } ClassFunction(stdPower){ - power_set_state(MIN(0, (getIntValue(args[0]) % POWER_OFF_REBOOT))); + power_set_state(MAX(0, (getIntValue(args[0]) % POWER_OFF_REBOOT))); return &emptyClass; } @@ -585,4 +585,4 @@ ClassFunctionTableEntry_t* searchStdLib(char* funcName, u8 *len) { *len = lenInternal; return ret; -} \ No newline at end of file +} From 62d93636d06504e6e35d846ead03f5f0cf4f4da3 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Wed, 28 Jul 2021 21:52:50 +0200 Subject: [PATCH 55/62] SCRIPT_ONLY:make --Exit-- selectable so you can't accidentally power off --- source/script/parser.c | 3 +++ source/tegraexplorer/mainmenu.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/script/parser.c b/source/script/parser.c index 3b2ed8b..3d92de4 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -560,6 +560,9 @@ ParserRet_t parseScript(char* in, u32 len) { vecAdd(&staticVariableHolder, a); CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); op.variable = reference; + vecAdd(&lastFunc->operations, op); + op.token = EquationSeperator; + op.lineNumber = lineNumber; } } else { diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index f94aadf..52337eb 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -65,8 +65,10 @@ MenuEntry_t mainMenuEntries[] = { [MainPartitionSd] = {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "Partition the sd"}, [MainViewKeys] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "View dumped keys"}, [MainViewCredits] = {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "Credits"}, - #endif [MainExit] = {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "\n-- Exit --"}, + #else + [MainExit] = {.optionUnion = COLORTORGB(COLOR_WHITE), .name = "\n-- Exit --"}, + #endif [MainPowerOff] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Power off"}, [MainRebootRCM] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot to RCM"}, [MainRebootNormal] = {.optionUnion = COLORTORGB(COLOR_VIOLET), .name = "Reboot normally"}, From 3f30b6c027af2a3d6a631d069654e2aac529051f Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Thu, 29 Jul 2021 09:42:20 +0200 Subject: [PATCH 56/62] reverting []() 'fix' --- source/script/parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/script/parser.c b/source/script/parser.c index 3d92de4..9323ff2 100644 --- a/source/script/parser.c +++ b/source/script/parser.c @@ -560,9 +560,11 @@ ParserRet_t parseScript(char* in, u32 len) { vecAdd(&staticVariableHolder, a); CreateVariableReferenceStatic((Variable_t*)(staticVariableHolder.count - 1)); op.variable = reference; + /* vecAdd(&lastFunc->operations, op); op.token = EquationSeperator; op.lineNumber = lineNumber; + */ } } else { From aa826641872bd3a0adf55631ab2e5d29095d4d7a Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Fri, 30 Jul 2021 23:11:57 +0200 Subject: [PATCH 57/62] re-enable startup.te --- source/fs/fsutils.c | 1 + source/main.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/fs/fsutils.c b/source/fs/fsutils.c index 8217e73..6efa3aa 100644 --- a/source/fs/fsutils.c +++ b/source/fs/fsutils.c @@ -47,6 +47,7 @@ char *GetFileAttribs(FSEntry_t entry){ return ret; } +// Returns 1 if a file exists, 0 if it does not bool FileExists(const char* path){ FRESULT fr; FILINFO fno; diff --git a/source/main.c b/source/main.c index 1c9288b..78c8507 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(); From 0b3d4bf55c43ca7734d5f228c44761b30f65f9ee Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sat, 31 Jul 2021 23:07:49 +0200 Subject: [PATCH 58/62] i'm stupid, again --- source/script/arrayClass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/script/arrayClass.c b/source/script/arrayClass.c index fdc10c1..ae4c075 100644 --- a/source/script/arrayClass.c +++ b/source/script/arrayClass.c @@ -86,7 +86,7 @@ ClassFunction(arraySlice) { s64 skipAmount = getIntValue(*args); s64 takeAmount = getIntValue(args[1]); - if (caller->solvedArray.vector.count < (skipAmount + takeAmount) || skipAmount <= 0 || takeAmount <= 0) { + if (caller->solvedArray.vector.count < (skipAmount + takeAmount) || skipAmount < 0 || takeAmount <= 0) { SCRIPT_FATAL_ERR("Slicing out of range of array with len %d", (int)caller->solvedArray.vector.count); } From f5fa98c7258b6d04a29b4aa479a089b84a59a6aa Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 1 Aug 2021 19:19:52 +0200 Subject: [PATCH 59/62] possibly fix script EOF endings? --- source/storage/nx_sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/storage/nx_sd.c b/source/storage/nx_sd.c index 8e4eb56..f122380 100644 --- a/source/storage/nx_sd.c +++ b/source/storage/nx_sd.c @@ -194,7 +194,8 @@ void *sd_file_read(const char *path, u32 *fsize) if (fsize) *fsize = size; - void *buf = malloc(size); + char *buf = malloc(size + 1); + buf[size] = '\0'; if (f_read(&fp, buf, size, NULL) != FR_OK) { From c9bb7e7766c76cd75eb782e7531c6a0ab6129165 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Sun, 1 Aug 2021 19:29:04 +0200 Subject: [PATCH 60/62] Add some fuse features --- source/script/standardLibrary.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 27efb02..3f4022b 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -26,6 +26,7 @@ #include "../fs/fsutils.h" #include #include "../storage/emmcfile.h" +#include #endif // Takes [int, function]. Returns elseable. ClassFunction(stdIf) { @@ -461,6 +462,14 @@ ClassFunction(stdPower){ return &emptyClass; } +ClassFunction(stdIsPatched){ + return newIntVariablePtr(fuse_check_patched_rcm()); +} + +ClassFunction(stdHwType){ + return newIntVariablePtr(fuse_read_hw_type()); +} + #else #define STUBBED(name) ClassFunction(name) { return newIntVariablePtr(0); } @@ -543,6 +552,8 @@ ClassFunctionTableEntry_t standardFunctionDefenitions[] = { {"emmcwrite", stdEmmcFileWrite, 2, twoStringArgStd}, {"emummcread", stdEmummcFileRead, 2, twoStringArgStd}, {"emummcwrite", stdEmummcFileWrite, 2, twoStringArgStd}, + {"fuse_patched", stdIsPatched, 0, 0}, + {"fuse_hwtype", stdHwType, 0, 0}, // FileSystem // Dir From 9a860252919128269ae9466d867f3f78253eea36 Mon Sep 17 00:00:00 2001 From: bleck9999 <55853712+bleck9999@users.noreply.github.com> Date: Sun, 1 Aug 2021 18:42:31 +0100 Subject: [PATCH 61/62] woah fuse features --- ts-minifier.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ts-minifier.py b/ts-minifier.py index aefa81d..a036e9b 100644 --- a/ts-minifier.py +++ b/ts-minifier.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 bleck9999 # https://github.com/bleck9999/ts-minifier -# Version: 85700fdd +# Version: 91345ce1 import argparse import re @@ -10,9 +10,9 @@ sub_funcs = {'while': "_h", 'print': "_p", 'println': "_l", 'mountsys': "_s", 'm 'exit': "_q", 'break': "_b", 'dict': "_d", 'setpixel': "_y", 'readdir': "_i", 'copyfile': "_c", 'mkdir': "_k", 'ncatype': "_n", 'pause': "_w", 'color': "_a", 'menu': "__", 'emu': "_u", 'clear': "_x", 'timer': "_t", 'deldir': "_g", 'fsexists': "_f", 'delfile': "_z", "copydir": "c_", - "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "w_", "setpixels": "y_", "printpos": "p_", - "emmcread": "e_", "emmcwrite": "f_", "emummcread": "r_", "emummcwrite": "s_", "escapepath": "x_", - "combinepath": "a_", "cwd": "d_", "power": "o_"} + "movefile": "_v", "payload": "_j", "readfile": "_o", "writefile": "_W", "setpixels": "_Y", "printpos": "_P", + "emmcread": "_E", "emmcwrite": "_F", "emummcread": "_R", "emummcwrite": "_S", "escapepath": "_X", + "combinepath": "_A", "cwd": "_D", "power": "_O", "fuse_patched": "_M", "fuse_hwtype": "_N"} replace_functions = False From 2d6c6593af607aed76e0a9d4d908589490de4640 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 2 Aug 2021 00:14:43 +0200 Subject: [PATCH 62/62] i forgot COPY_MODE_PRINT at FileCopy --- source/script/standardLibrary.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/script/standardLibrary.c b/source/script/standardLibrary.c index 3f4022b..48b4f56 100644 --- a/source/script/standardLibrary.c +++ b/source/script/standardLibrary.c @@ -274,7 +274,7 @@ ClassFunction(stdPause){ // Takes [str, str]. Returns int (0=success). 0: src path, 1: dst path ClassFunction(stdFileCopy){ - ErrCode_t e = FileCopy(args[0]->string.value, args[1]->string.value, 0); + ErrCode_t e = FileCopy(args[0]->string.value, args[1]->string.value, COPY_MODE_PRINT); return newIntVariablePtr(e.err); } @@ -507,6 +507,8 @@ STUBBED(stdGetCwd) STUBBED(stdPower) STUBBED(stdSetPrintPos) STUBBED(stdSetPixels) +STUBBED(stdIsPatched) +STUBBED(stdHwType) #endif u8 oneIntoneFunction[] = { IntClass, FunctionClass };