1
0
Fork 0
mirror of https://github.com/suchmememanyskill/TegraExplorer.git synced 2024-11-22 11:56:42 +00:00

tsv3 start ig

This commit is contained in:
suchmememanyskill 2021-07-09 22:56:13 +02:00
parent 804ba3495c
commit 2ddc7ae2a9
51 changed files with 3188 additions and 1749 deletions

4
.gitignore vendored
View file

@ -7,4 +7,8 @@ loader/payload_00.h
loader/payload_01.h
source/script/Debug
source/script/*.te
source/script/.vs
*.exe

View file

@ -11,11 +11,12 @@
#include <libs/fatfs/ff.h>
#include "../../utils/utils.h"
#include "../../keys/nca.h"
#include "../../script/lexer.h"
#include "../../script/parser.h"
#include "../../script/variables.h"
#include <storage/nx_sd.h>
#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){

View file

@ -11,9 +11,6 @@
#include <libs/fatfs/ff.h>
#include "../../utils/utils.h"
#include "../../keys/nca.h"
#include "../../script/lexer.h"
#include "../../script/parser.h"
#include "../../script/variables.h"
#include <storage/nx_sd.h>
#include "../fscopy.h"

View file

@ -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();

View file

@ -0,0 +1,91 @@
#ifdef WIN32
#include <stdio.h>
#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

View file

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{b4ea4793-03fc-4c25-b69b-a5fbad2d89d5}</ProjectGuid>
<RootNamespace>ABadIdeaVersion3</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<EnableASAN>false</EnableASAN>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<Optimization>MinSpace</Optimization>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ABadIdeaVersion3.c" />
<ClCompile Include="arrayClass.c" />
<ClCompile Include="arrayReferenceClass.c" />
<ClCompile Include="eval.c" />
<ClCompile Include="functionClass.c" />
<ClCompile Include="garbageCollector.c" />
<ClCompile Include="genericClass.c" />
<ClCompile Include="intClass.c" />
<ClCompile Include="model.c" />
<ClCompile Include="parser.c" />
<ClCompile Include="scriptError.c" />
<ClCompile Include="standardLibrary.c" />
<ClCompile Include="StringClass.c" />
<ClCompile Include="unsolvedArrayClass.c" />
<ClCompile Include="vector.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="arrayClass.h" />
<ClInclude Include="arrayReferenceClass.h" />
<ClInclude Include="compat.h" />
<ClInclude Include="dictionaryClass.h" />
<ClInclude Include="eval.h" />
<ClInclude Include="functionClass.h" />
<ClInclude Include="garbageCollector.h" />
<ClInclude Include="genericClass.h" />
<ClInclude Include="intClass.h" />
<ClInclude Include="model.h" />
<ClInclude Include="parser.h" />
<ClInclude Include="scriptError.h" />
<ClInclude Include="standardLibrary.h" />
<ClInclude Include="StringClass.h" />
<ClInclude Include="unsolvedArrayClass.h" />
<ClInclude Include="vector.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\Classes">
<UniqueIdentifier>{c245ac36-a649-432b-a663-98ff9d02d3f4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\String">
<UniqueIdentifier>{e4d90dab-a1e0-4a27-82a1-dc2c6b81f0bd}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\Generic">
<UniqueIdentifier>{1aacfe02-949c-4394-b408-28d73d702918}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\Array">
<UniqueIdentifier>{5878f4a8-cac0-40aa-8866-6109bf6688ab}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\Dictionary">
<UniqueIdentifier>{ec7391f8-d60e-46eb-965e-c2d84d48d784}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\Function">
<UniqueIdentifier>{015ca379-a813-4d13-a929-3b0efe72bb02}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Classes\Int">
<UniqueIdentifier>{64738969-63b9-4d0e-85b9-d9a63a7e36b3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABadIdeaVersion3.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vector.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="parser.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="model.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="eval.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="genericClass.c">
<Filter>Source Files\Classes\Generic</Filter>
</ClCompile>
<ClCompile Include="garbageCollector.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="functionClass.c">
<Filter>Source Files\Classes\Function</Filter>
</ClCompile>
<ClCompile Include="StringClass.c">
<Filter>Source Files\Classes\String</Filter>
</ClCompile>
<ClCompile Include="unsolvedArrayClass.c">
<Filter>Source Files\Classes\Array</Filter>
</ClCompile>
<ClCompile Include="arrayClass.c">
<Filter>Source Files\Classes\Array</Filter>
</ClCompile>
<ClCompile Include="intClass.c">
<Filter>Source Files\Classes\Int</Filter>
</ClCompile>
<ClCompile Include="arrayReferenceClass.c">
<Filter>Source Files\Classes\Array</Filter>
</ClCompile>
<ClCompile Include="standardLibrary.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="scriptError.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="compat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="model.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="parser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="eval.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="garbageCollector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dictionaryClass.h">
<Filter>Source Files\Classes\Dictionary</Filter>
</ClInclude>
<ClInclude Include="arrayClass.h">
<Filter>Source Files\Classes\Array</Filter>
</ClInclude>
<ClInclude Include="intClass.h">
<Filter>Source Files\Classes\Int</Filter>
</ClInclude>
<ClInclude Include="StringClass.h">
<Filter>Source Files\Classes\String</Filter>
</ClInclude>
<ClInclude Include="unsolvedArrayClass.h">
<Filter>Source Files\Classes\Array</Filter>
</ClInclude>
<ClInclude Include="functionClass.h">
<Filter>Source Files\Classes\Function</Filter>
</ClInclude>
<ClInclude Include="genericClass.h">
<Filter>Source Files\Classes\Generic</Filter>
</ClInclude>
<ClInclude Include="arrayReferenceClass.h">
<Filter>Source Files\Classes\Array</Filter>
</ClInclude>
<ClInclude Include="standardLibrary.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="scriptError.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View file

@ -0,0 +1,60 @@
#include "StringClass.h"
#include "compat.h"
#include "intClass.h"
#include <string.h>
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));
}

View file

@ -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);

View file

@ -1,502 +0,0 @@
#include "args.h"
#include "types.h"
#include "functions.h"
#include "variables.h"
#include <string.h>
#include <mem/heap.h>
#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;
}

View file

@ -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);

259
source/script/arrayClass.c Normal file
View file

@ -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 <string.h>
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));
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "model.h"
#include "genericClass.h"
Variable_t getArrayMember(Variable_t* var, char* memberName);

View file

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

View file

@ -0,0 +1,5 @@
#pragma once
#include "model.h"
#include "genericClass.h"
Variable_t getArrayReferenceMember(Variable_t* var, char* memberName);

21
source/script/compat.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#ifdef WIN32
#include <stdio.h>
#include <malloc.h>
#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 <mem/heap.h>
#include "../utils/vector.h"
#include "../utils/utils.h"
#endif

View file

@ -0,0 +1,3 @@
#pragma once
#include "model.h"
#include "genericClass.h"

266
source/script/eval.c Normal file
View file

@ -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 <string.h>
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;
}

19
source/script/eval.h Normal file
View file

@ -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);

View file

@ -0,0 +1,67 @@
#include "functionClass.h"
#include "compat.h"
#include "model.h"
#include <malloc.h>
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;
}

View file

@ -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);

View file

@ -1,529 +0,0 @@
#include "types.h"
#include "args.h"
#include "variables.h"
#include <string.h>
#include "../gfx/gfx.h"
#include <mem/heap.h>
#include "lexer.h"
#include <storage/nx_sd.h>
#include "../fs/fsutils.h"
#include "../gfx/gfxutils.h"
#include "../hid/hid.h"
#include <utils/util.h>
#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("<Wait %d seconds> \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);
}

View file

@ -1,4 +0,0 @@
#pragma once
#include "variables.h"
Variable_t executeFunction(scriptCtx_t* ctx, char* func_name, lexarToken_t* start, u32 len);

View file

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

View file

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

View file

@ -0,0 +1,264 @@
#include "genericClass.h"
#include "model.h"
#include "intClass.h"
#include "compat.h"
#include "eval.h"
#include <string.h>
#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;
}

View file

@ -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);

76
source/script/intClass.c Normal file
View file

@ -0,0 +1,76 @@
#include "intClass.h"
#include "compat.h"
#include <malloc.h>
#include <string.h>
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));
}

13
source/script/intClass.h Normal file
View file

@ -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);

View file

@ -1,308 +0,0 @@
#include "lexer.h"
#include "types.h"
#include "args.h"
#include <mem/heap.h>
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;
}

View file

@ -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);

43
source/script/model.c Normal file
View file

@ -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 };

269
source/script/model.h Normal file
View file

@ -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 <libs/nx_savedata/save.h>
#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()

View file

@ -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 <mem/heap.h>
#include "../hid/hid.h"
#include "model.h"
#include "compat.h"
#include "compat.h"
#include "parser.h"
#include <stdlib.h>
#include <string.h>
#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);
}
}
}

View file

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

30
source/script/saveClass.c Normal file
View file

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

View file

@ -0,0 +1,4 @@
#include "model.h"
#include "genericClass.h"
Variable_t getSaveMember(Variable_t* var, char* memberName);

View file

@ -0,0 +1,16 @@
#include "scriptError.h"
#include "compat.h"
#include <stdarg.h>
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);
}

View file

@ -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__)

View file

@ -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 <string.h>
#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;
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "model.h"
ClassFunctionTableEntry_t* searchStdLib(char* funcName);

View file

@ -1,145 +0,0 @@
#pragma once
#include <utils/types.h>
#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)

View file

@ -0,0 +1,187 @@
#include "unsolvedArrayClass.h"
#include "eval.h"
#include "compat.h"
#include "intClass.h"
#include "scriptError.h"
#include "garbageCollector.h"
#include <string.h>
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));
}

View file

@ -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);

View file

@ -1,105 +0,0 @@
#include "variables.h"
#include "types.h"
#include <string.h>
#include <mem/heap.h>
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];
}

View file

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

111
source/script/vector.c Normal file
View file

@ -0,0 +1,111 @@
#ifdef WIN32
#include "vector.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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

24
source/script/vector.h Normal file
View file

@ -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

View file

@ -1,4 +1,5 @@
#include "vector.h"
#include "../gfx/gfx.h"
#include <string.h>
#include <mem/heap.h>
@ -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;
}

View file

@ -1,6 +1,8 @@
#pragma once
#include <utils/types.h>
#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))