1
0
Fork 0
mirror of https://github.com/suchmememanyskill/TegraExplorer.git synced 2024-11-13 23:46:42 +00:00
TegraExplorer/source/script/eval.c
2021-07-23 14:03:49 +02:00

276 lines
No EOL
6.9 KiB
C

#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);
runtimeVars.count = 0;
}
Variable_t* opToVar(Operator_t* op, Callback_SetVar_t *setCallback, u8 possibleCallArg) {
Variable_t* var = NULL;
CallArgs_t* args = NULL;
if ((op + 1)->token == CallArgs && possibleCallArg)
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->function.len = op->variable.staticFunctionLen;
var->reference = 1;
if (!strcmp(var->function.builtInPtr->name,"while")) {
var->function.firstArgAsFunction = 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("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);
}
removePendingReference(curRes);
removePendingReference(set->setVar);
// 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, (len - i) > 1);
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, (len - i) > 1);
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;
}