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])