6 #include <initializer_list>
14 #include <string_view>
15 #include <unordered_map>
16 #include <unordered_set>
55 using std::initializer_list;
57 using std::make_unique;
67 using std::string_view;
68 using std::stringstream;
70 using std::unique_ptr;
71 using std::unordered_map;
72 using std::unordered_set;
108 const string MinitScript::OPERATOR_CHARS =
"+-!~/%<>=&^|";
110 vector<MinitScript::DataType*> MinitScript::dataTypes;
111 MinitScript::ShutdownRAII MinitScript::shutdownRAII(MinitScript::dataTypes);
113 const string MinitScript::METHOD_SCRIPTCALL =
"script.call";
114 const string MinitScript::METHOD_SCRIPTCALLSTACKLET =
"script.callStacklet";
115 const string MinitScript::METHOD_SCRIPTCALLBYINDEX =
"script.callByIndex";
116 const string MinitScript::METHOD_SCRIPTCALLSTACKLETBYINDEX =
"script.callStackletByIndex";
118 const string MinitScript::METHOD_ENABLENAMEDCONDITION =
"script.enableNamedCondition";
119 const string MinitScript::METHOD_DISABLENAMEDCONDITION =
"script.disableNamedCondition";
121 const string MinitScript::Variable::TYPENAME_NONE =
"";
122 const string MinitScript::Variable::TYPENAME_NULL =
"Null";
123 const string MinitScript::Variable::TYPENAME_BOOLEAN =
"Boolean";
124 const string MinitScript::Variable::TYPENAME_INTEGER =
"Integer";
125 const string MinitScript::Variable::TYPENAME_FLOAT =
"Float";
126 const string MinitScript::Variable::TYPENAME_FUNCTION =
"Function";
127 const string MinitScript::Variable::TYPENAME_STACKLET =
"Stacklet";
128 const string MinitScript::Variable::TYPENAME_NUMBER =
"Number";
129 const string MinitScript::Variable::TYPENAME_MIXED =
"Mixed";
130 const string MinitScript::Variable::TYPENAME_STRING =
"String";
131 const string MinitScript::Variable::TYPENAME_BYTEARRAY =
"ByteArray";
132 const string MinitScript::Variable::TYPENAME_ARRAY =
"Array";
133 const string MinitScript::Variable::TYPENAME_MAP =
"Map";
134 const string MinitScript::Variable::TYPENAME_SET =
"Set";
136 const vector<string> MinitScript::Method::CONTEXTFUNCTIONS_ALL = {};
138 void MinitScript::initialize() {
144 HTTPDownloadClientClass::initialize();
147 const string MinitScript::getBaseClassHeader() {
148 return "minitscript/minitscript/MinitScript.h";
151 const string MinitScript::getBaseClass() {
152 return "minitscript::minitscript::MinitScript";
155 const vector<string> MinitScript::getTranspilationUnits() {
165 MINITSCRIPT_DATA +
"/src/minitscript/minitscript/HTTPDownloadClientClass.cpp",
178 MinitScript::MinitScript() {
180 for (
auto dataType: dataTypes) {
181 if (dataType->isRequiringGarbageCollection() ==
false)
continue;
183 auto scriptContext = dataType->createScriptContext();
184 scriptContext->setMinitScript(
this);
185 scriptContext->setIndex(garbageCollectionDataTypes.size());
187 garbageCollectionDataTypes.emplace_back(dataType,scriptContext);
188 garbageCollectionScriptContextsByDataType[dataType->getType()] = scriptContext;
194 MinitScript::~MinitScript() {
195 for (
const auto& [methodName, method]: this->methods)
delete method;
196 for (
const auto& [stateMachineStateId, stateMachineState]: this->stateMachineStates)
delete stateMachineState;
197 while (scriptStateStack.empty() ==
false) popScriptState();
199 for (
auto& garbageCollectionDataType: garbageCollectionDataTypes) garbageCollectionDataType.dataType->deleteScriptContext(garbageCollectionDataType.context);
203 auto stateMachineStateIt = stateMachineStates.find(state->
getId());
204 if (stateMachineStateIt != stateMachineStates.end()) {
205 _Console::printLine(
"MinitScript::registerStateMachineState(): " + scriptFileName +
": State with id + " + to_string(state->
getId()) +
", name " + state->
getName() +
" already registered.");
208 stateMachineStates[state->
getId()] = state;
211 void MinitScript::initializeNative() {
214 void MinitScript::complain(
const string& methodName,
const SubStatement& subStatement) {
215 auto argumentsInformation = getArgumentsInformation(methodName);
216 if (argumentsInformation.empty() ==
true) argumentsInformation =
"None";
217 auto errorMessageDetails = getSubStatementInformation(subStatement) +
": " + methodName +
"(...): Argument mismatch: expected arguments: " + argumentsInformation;
222 "An method usage complain has occurred: " +
225 errorSubStatement = subStatement;
228 void MinitScript::complain(
const string& methodName,
const SubStatement& subStatement,
const string& message) {
229 auto errorMessageDetails = getSubStatementInformation(subStatement) +
": " + methodName +
"(...): " + message;
234 "An method usage complain has occurred: " +
237 errorSubStatement = subStatement;
240 void MinitScript::complainOperator(
const string& methodName,
const string& operatorString,
const SubStatement& subStatement) {
241 auto argumentsInformation = getArgumentsInformation(methodName);
242 if (argumentsInformation.empty() ==
true) argumentsInformation =
"None";
243 auto errorMessageDetails = getSubStatementInformation(subStatement) +
": '" + operatorString +
"': Argument mismatch: expected arguments: " + argumentsInformation;
248 (isOperator(operatorString) ==
true?
249 "An operator usage complain has occurred: ":
250 "An method usage complain has occurred: "
254 errorSubStatement = subStatement;
257 void MinitScript::complainOperator(
const string& methodName,
const string& operatorString,
const SubStatement& subStatement,
const string& message) {
258 auto errorMessageDetails = getSubStatementInformation(subStatement) +
": '" + operatorString +
"': " + message;
263 (isOperator(operatorString) ==
true?
264 "An operator usage complain has occurred: ":
265 "An method usage complain has occurred: "
269 errorSubStatement = subStatement;
272 void MinitScript::registerMethod(
Method* method) {
274 if (methodsIt != methods.end()) {
281 void MinitScript::registerDataType(
DataType* dataType) {
283 dataTypes.push_back(dataType);
286 void MinitScript::executeNextStatement() {
287 auto& scriptState = getScriptState();
288 if (scriptState.scriptIdx == SCRIPTIDX_NONE || scriptState.statementIdx == STATEMENTIDX_NONE || scriptState.running ==
false)
return;
290 const auto& script = scripts[scriptState.scriptIdx];
291 if (script.statements.empty() ==
true)
return;
293 if (scriptState.gotoStatementIdx != STATEMENTIDX_NONE) {
294 scriptState.statementIdx = scriptState.gotoStatementIdx;
295 scriptState.gotoStatementIdx = STATEMENTIDX_NONE;
298 const auto& statement = script.statements[scriptState.statementIdx];
299 const auto& syntaxTree = script.syntaxTree[scriptState.statementIdx];
301 if (scriptState.statementIdx == STATEMENTIDX_FIRST) emitted =
false;
303 executeStatement(syntaxTree, statement);
305 if (emitted ==
true)
return;
307 scriptState.statementIdx++;
308 if (scriptState.statementIdx >= script.statements.size()) {
309 scriptState.scriptIdx = SCRIPTIDX_NONE;
310 scriptState.statementIdx = STATEMENTIDX_NONE;
311 setScriptStateState(STATEMACHINESTATE_WAIT_FOR_CONDITION);
315 bool MinitScript::parseStatement(
const string_view& executableStatement, string_view& methodName, vector<ParserArgument>& arguments,
const Statement& statement,
string& accessObjectMemberStatement) {
316 if (VERBOSE ==
true)
_Console::printLine(
"MinitScript::parseStatement(): " + getStatementInformation(statement) +
": '" +
string(executableStatement) +
"'");
318 string_view objectMemberAccessObject;
319 string_view objectMemberAccessMethod;
320 int executableStatementStartIdx = 0;
321 auto objectMemberAccess = getObjectMemberAccess(executableStatement, objectMemberAccessObject, objectMemberAccessMethod, executableStatementStartIdx, statement);
322 auto bracketCount = 0;
323 auto squareBracketCount = 0;
324 auto curlyBracketCount = 0;
326 auto methodStart = string::npos;
327 auto methodEnd = string::npos;
328 auto argumentStart = string::npos;
329 auto argumentEnd = string::npos;
330 auto quotedArgumentStart = string::npos;
331 auto quotedArgumentEnd = string::npos;
332 auto argumentSubLineIdx = -1;
337 auto i = executableStatementStartIdx;
339 auto hasNextArgument = [&]() ->
bool {
341 for (i++; i < executableStatement.size(); i++) {
342 auto c = executableStatement[i];
350 auto createArgument = [&]() {
352 if (quotedArgumentStart != string::npos) {
353 auto argumentLength = quotedArgumentEnd - quotedArgumentStart + 1;
354 if (argumentLength > 0) arguments.emplace_back(
_StringTools::viewTrim(string_view(&executableStatement[quotedArgumentStart], argumentLength)), argumentSubLineIdx);
355 quotedArgumentStart = string::npos;
356 quotedArgumentEnd = string::npos;
357 argumentSubLineIdx = -1;
359 if (argumentStart != string::npos) {
360 if (argumentEnd == string::npos) argumentEnd = i - 1;
361 auto argumentLength = argumentEnd - argumentStart + 1;
362 if (argumentLength > 0) arguments.emplace_back(
_StringTools::viewTrim(string_view(&executableStatement[argumentStart], argumentLength)), argumentSubLineIdx);
363 argumentStart = string::npos;
364 argumentEnd = string::npos;
365 argumentSubLineIdx = -1;
369 auto isObjectMemberAccess = [&]() ->
bool {
373 for (; j < executableStatement.size() &&
_Character::isSpace(executableStatement[j]) ==
true; j++);
375 if (j >= executableStatement.size())
return false;
377 if (executableStatement[j++] !=
'-')
return false;
379 if (j >= executableStatement.size())
return false;
381 if (executableStatement[j++] !=
'>')
return false;
386 methodStart = executableStatementStartIdx;
388 for (; i < executableStatement.size(); i++) {
390 auto c = executableStatement[i];
392 if (squareBracketCount == 0 && curlyBracketCount == 0 && ((c ==
'"' || c ==
'\'') && lc !=
'\\')) {
396 if (bracketCount == 1) {
397 argumentStart = string::npos;
398 quotedArgumentStart = i;
399 argumentSubLineIdx = subLineIdx;
407 if (bracketCount == 1) {
408 quotedArgumentEnd = i;
410 if (isObjectMemberAccess() ==
true) {
412 if (quotedArgumentStart != string::npos) {
413 argumentStart = quotedArgumentStart;
414 argumentEnd = string::npos;
415 quotedArgumentStart = string::npos;
416 quotedArgumentEnd = string::npos;
436 if (bracketCount == 1) {
441 if (hasNextArgument() ==
true) {
444 argumentSubLineIdx = subLineIdx;
458 if (bracketCount == 0) createArgument();
461 if (c ==
'[' && curlyBracketCount == 0) {
462 squareBracketCount++;
465 if (c ==
']' && curlyBracketCount == 0) {
466 squareBracketCount--;
477 if (squareBracketCount == 0 && curlyBracketCount == 0 && bracketCount == 1 && c ==
',') {
478 if (bracketCount == 1) {
483 if (hasNextArgument() ==
true) {
486 argumentSubLineIdx = subLineIdx;
497 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
501 if (methodStart != string::npos) {
503 if (methodEnd == string::npos) methodEnd = i - 1;
505 methodName =
_StringTools::viewTrim(string_view(&executableStatement[methodStart], methodEnd - methodStart + 1));
509 if (objectMemberAccess ==
true) {
511 string_view evaluateMemberAccessMethodName;
512 vector<ParserArgument> evaluateMemberAccessArguments;
515 auto objectMemberAccessObjectVariable = viewIsVariableAccess(objectMemberAccessObject);
518 accessObjectMemberStatement.reserve(16384);
519 auto idx = accessObjectMemberStatement.size();
520 accessObjectMemberStatement+=
"internal.script.evaluateMemberAccess";
521 evaluateMemberAccessMethodName = string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx);
522 accessObjectMemberStatement+=
"(";
523 idx = accessObjectMemberStatement.size();
524 accessObjectMemberStatement+= objectMemberAccessObjectVariable ==
true?
"\"" + string(objectMemberAccessObject) +
"\"":
"null";
525 evaluateMemberAccessArguments.emplace_back(string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx), 0);
526 idx = accessObjectMemberStatement.size();
527 accessObjectMemberStatement+=
", ";
528 idx = accessObjectMemberStatement.size();
529 accessObjectMemberStatement+= objectMemberAccessObjectVariable ==
true?
"null":string(objectMemberAccessObject);
530 evaluateMemberAccessArguments.emplace_back(string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx), 0);
531 accessObjectMemberStatement+=
", ";
532 idx = accessObjectMemberStatement.size();
533 accessObjectMemberStatement+=
"\"" + string(methodName) +
"\"";
534 evaluateMemberAccessArguments.emplace_back(string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx), 0);
535 for (
const auto& argument: arguments) {
536 auto argumentVariable = viewIsVariableAccess(argument.argument);
537 accessObjectMemberStatement+=
", ";
538 idx = accessObjectMemberStatement.size();
539 accessObjectMemberStatement+= argumentVariable ==
true?
"\"" + string(argument.argument) +
"\"":
"null";
540 evaluateMemberAccessArguments.emplace_back(string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx), 0);
541 accessObjectMemberStatement+=
", ";
542 idx = accessObjectMemberStatement.size();
543 accessObjectMemberStatement+= argumentVariable ==
true?
"null":string(argument.argument);
544 evaluateMemberAccessArguments.emplace_back(string_view(&accessObjectMemberStatement.data()[idx], accessObjectMemberStatement.size() - idx), 0);
546 accessObjectMemberStatement+=
")";
548 methodName = evaluateMemberAccessMethodName;
549 arguments = evaluateMemberAccessArguments;
553 if (VERBOSE ==
true) {
558 for (
const auto& argument: arguments) {
566 if (bracketCount != 0) {
568 _Console::printLine(getStatementInformation(statement) +
": " +
string(executableStatement) +
"': Unbalanced bracket count: " + to_string(
_Math::abs(bracketCount)) +
" " + (bracketCount < 0?
"too much closed":
"still open"));
570 parseErrors.push_back(
string(executableStatement) +
": Unbalanced bracket count: " + to_string(
_Math::abs(bracketCount)) +
" " + (bracketCount < 0?
"too much closed":
"still open"));
575 if (squareBracketCount != 0) {
577 _Console::printLine(getStatementInformation(statement) +
": " +
string(executableStatement) +
"': Unbalanced square bracket count: " + to_string(
_Math::abs(squareBracketCount)) +
" " + (squareBracketCount < 0?
"too much closed":
"still open"));
579 parseErrors.push_back(
string(executableStatement) +
": Unbalanced square bracket count: " + to_string(
_Math::abs(squareBracketCount)) +
" " + (squareBracketCount < 0?
"too much closed":
"still open"));
584 if (curlyBracketCount != 0) {
586 _Console::printLine(getStatementInformation(statement) +
": " +
string(executableStatement) +
"': Unbalanced curly bracket count: " + to_string(
_Math::abs(curlyBracketCount)) +
" " + (curlyBracketCount < 0?
"too much closed":
"still open"));
588 parseErrors.push_back(
string(executableStatement) +
": Unbalanced curly bracket count: " + to_string(
_Math::abs(curlyBracketCount)) +
" " + (curlyBracketCount < 0?
"too much closed":
"still open"));
600 if (syntaxTree.
type == SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL) {
601 return initializeVariable(syntaxTree.
value);
604 vector<Variable> arguments;
607 for (
const auto& argument: syntaxTree.
arguments) {
608 switch (argument.type) {
609 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL:
611 arguments.push_back(initializeVariable(argument.value));
614 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:
615 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD:
617 arguments.push_back(executeStatement(argument, statement));
625 if (VERBOSE ==
true) {
629 if (syntaxTree.
type == SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION) {
631 span argumentsSpan(arguments);
632 call(syntaxTree.
getScriptIdx(), argumentsSpan, returnValue);
636 if (syntaxTree.
type == SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_STACKLET) {
638 span argumentsSpan(arguments);
639 callStacklet(syntaxTree.
getScriptIdx(), argumentsSpan, returnValue);
643 if (syntaxTree.
type == SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD) {
647 if (VALIDATION ==
true) {
648 auto argumentIdx = 0;
649 for (
const auto& argumentType: method->getArgumentTypes()) {
650 auto argumentOk =
true;
652 if (argumentType.nullable ==
true &&
653 argumentIdx >= 0 && argumentIdx < arguments.size() &&
654 arguments[argumentIdx].getType() == TYPE_NULL) {
658 switch(argumentType.type) {
664 argumentOk = getBooleanValue(arguments, argumentIdx, booleanValue, argumentType.optional);
669 int64_t integerValue;
670 argumentOk = getIntegerValue(arguments, argumentIdx, integerValue, argumentType.optional);
676 argumentOk = getFloatValue(arguments, argumentIdx, floatValue, argumentType.optional);
679 case TYPE_PSEUDO_NUMBER:
682 argumentOk = getFloatValue(arguments, argumentIdx, floatValue, argumentType.optional);
685 case TYPE_PSEUDO_MIXED:
693 argumentOk = getStringValue(arguments, argumentIdx, stringValue, argumentType.optional);
699 argumentIdx < 0 || argumentIdx >= arguments.size()?
700 argumentType.optional:
701 arguments[argumentIdx].getType() == TYPE_BYTEARRAY;
707 argumentIdx < 0 || argumentIdx >= arguments.size()?
708 argumentType.optional:
709 arguments[argumentIdx].getType() == TYPE_ARRAY;
715 argumentIdx < 0 || argumentIdx >= arguments.size()?
716 argumentType.optional:
717 arguments[argumentIdx].getType() == TYPE_MAP;
723 argumentIdx < 0 || argumentIdx >= arguments.size()?
724 argumentType.optional:
725 arguments[argumentIdx].getType() == TYPE_SET;
732 argumentIdx < 0 || argumentIdx >= arguments.size()?
733 argumentType.optional:
734 arguments[argumentIdx].getType() == argumentType.type;
740 if (argumentOk ==
false) {
742 getStatementInformation(statement, syntaxTree.
subLineIdx) +
744 ": argument value @ " + to_string(argumentIdx) +
": expected " + Variable::getTypeAsString(argumentType.type) +
", but got: " + (argumentIdx < arguments.size()?arguments[argumentIdx].getAsString():
"nothing"));
748 if (method->isVariadic() ==
false && arguments.size() > method->getArgumentTypes().size()) {
750 getStatementInformation(statement, syntaxTree.
subLineIdx) +
752 ": too many arguments: expected: " + to_string(method->getArgumentTypes().size()) +
", got " + to_string(arguments.size()));
756 span argumentsSpan(arguments);
759 if (VALIDATION ==
true) {
760 if (method->isReturnValueNullable() ==
true && returnValue.
getType() == TYPE_NULL) {
763 if (MinitScript::Variable::isExpectedType(returnValue.
getType(), method->getReturnValueType()) ==
false) {
765 getStatementInformation(statement, syntaxTree.
subLineIdx) +
767 ": return value: expected " + Variable::getReturnTypeAsString(method->getReturnValueType(), method->isReturnValueNullable()) +
", but got: " + Variable::getReturnTypeAsString(returnValue.
getType(),
false));
777 bool MinitScript::createStatementSyntaxTree(
int scriptIdx,
const string_view& methodName,
const vector<ParserArgument>& arguments,
const Statement& statement,
SyntaxTreeNode& syntaxTree,
int subLineIdx) {
778 if (VERBOSE ==
true) {
780 auto getArgumentsAsString = [](
const vector<ParserArgument>& arguments) ->
const string {
781 string argumentsString;
782 for (
const auto& argument: arguments) argumentsString+= (argumentsString.empty() ==
false?
", ":
"") +
string(
"@") + to_string(argument.subLineIdx) + string(
"'") + string(argument.argument) + string(
"'");
783 return argumentsString;
786 _Console::printLine(
"MinitScript::createScriptStatementSyntaxTree(): " + getStatementInformation(statement) +
": " +
string(methodName) +
"(" + getArgumentsAsString(arguments) +
")");
789 auto functionScriptIdx = SCRIPTIDX_NONE;
793 auto functionsIt = functions.find(
string(methodName));
794 if (functionsIt != functions.end()) {
795 functionScriptIdx = functionsIt->second;
800 auto methodsIt = methods.find(
string(methodName));
801 if (methodsIt != methods.end()) {
802 method = methodsIt->second;
807 vector<bool> argumentReferences(0);
808 if (functionScriptIdx != SCRIPTIDX_NONE) {
809 const auto& script = scripts[functionScriptIdx];
810 if (script.type == Script::TYPE_STACKLET) {
811 if (arguments.empty() ==
false) {
812 _Console::printLine(getStatementInformation(statement) +
": A stacklet must not be called with any arguments: " +
string(methodName));
814 parseErrors.push_back(getStatementInformation(statement) +
": A stacklet must not be called with any arguments: " +
string(methodName));
819 argumentReferences.resize(script.arguments.size());
820 auto argumentIdx = 0;
821 for (
const auto& argument: scripts[functionScriptIdx].arguments) {
822 argumentReferences[argumentIdx++] = argument.reference;
826 if (method !=
nullptr) {
828 auto argumentIdx = 0;
830 argumentReferences[argumentIdx++] = argument.reference;
833 auto argumentIdx = 0;
834 for (
const auto& argument: arguments) {
836 string_view accessObjectMemberObject;
837 string_view accessObjectMemberMethod;
838 int accessObjectMemberStartIdx;
839 vector<string_view> lamdaFunctionStackletArguments;
840 string_view lamdaFunctionStackletScriptCode;
841 int lamdaFunctionStackletLineIdx = statement.
line + subLineIdx + argument.subLineIdx;
842 if (viewIsLamdaFunction(argument.argument, lamdaFunctionStackletArguments, lamdaFunctionStackletScriptCode, lamdaFunctionStackletLineIdx) ==
true) {
844 createLamdaFunction(variable, lamdaFunctionStackletArguments, lamdaFunctionStackletScriptCode, lamdaFunctionStackletLineIdx,
false, statement);
845 SyntaxTreeNode subSyntaxTree(SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL, variable,
nullptr, {}, subLineIdx + argument.subLineIdx);
846 syntaxTree.
arguments.push_back(subSyntaxTree);
848 if (viewIsStacklet(argument.argument, lamdaFunctionStackletArguments, lamdaFunctionStackletScriptCode, lamdaFunctionStackletLineIdx) ==
true) {
851 if (scriptIdx != SCRIPTIDX_NONE) {
853 if (scripts[scriptIdx].type == Script::TYPE_FUNCTION) {
854 scopeName = scripts[scriptIdx].condition;
859 createStacklet(variable, scopeName, lamdaFunctionStackletArguments, lamdaFunctionStackletScriptCode, lamdaFunctionStackletLineIdx, statement);
860 SyntaxTreeNode subSyntaxTree(SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL, variable,
nullptr, {}, subLineIdx + argument.subLineIdx);
861 syntaxTree.
arguments.push_back(subSyntaxTree);
863 if (getObjectMemberAccess(argument.argument, accessObjectMemberObject, accessObjectMemberMethod, accessObjectMemberStartIdx, statement) ==
true) {
865 string_view subMethodName;
866 vector<ParserArgument> subArguments;
867 string accessObjectMemberStatement;
869 if (parseStatement(argument.argument, subMethodName, subArguments, statement, accessObjectMemberStatement) ==
true) {
871 if (createStatementSyntaxTree(scriptIdx, subMethodName, subArguments, statement, subSyntaxTree, subLineIdx + argument.
subLineIdx) ==
false) {
874 syntaxTree.
arguments.push_back(subSyntaxTree);
880 if (viewIsVariableAccess(argument.argument) ==
true) {
883 value.
setValue(deescape(argument.argument, statement));
886 argumentIdx >= argumentReferences.size() || argumentReferences[argumentIdx] ==
false?
887 (method !=
nullptr?
"getMethodArgumentVariable":
"getVariable"):
888 "getVariableReference";
892 auto methodsIt = methods.find(methodName);
893 if (methodsIt != methods.end()) {
894 method = methodsIt->second;
896 _Console::printLine(getStatementInformation(statement, subLineIdx + argument.subLineIdx) +
": Unknown method: " + methodName);
898 parseErrors.push_back(getStatementInformation(statement, subLineIdx + argument.subLineIdx) +
": Unknown method: " + methodName);
905 SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD,
908 initializer_list<SyntaxTreeNode>
911 SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL,
915 subLineIdx + argument.subLineIdx
918 subLineIdx + argument.subLineIdx
922 if (argument.argument.empty() ==
false &&
923 viewIsStringLiteral(argument.argument) ==
false &&
924 viewIsInitializer(argument.argument) ==
false &&
925 viewIsCall(argument.argument) ==
true) {
927 string_view subMethodName;
928 vector<ParserArgument> subArguments;
929 string accessObjectMemberStatement;
931 if (parseStatement(argument.argument, subMethodName, subArguments, statement, accessObjectMemberStatement) ==
true) {
933 if (createStatementSyntaxTree(scriptIdx, subMethodName, subArguments, statement, subSyntaxTree, subLineIdx + argument.
subLineIdx) ==
false) {
936 syntaxTree.
arguments.push_back(subSyntaxTree);
947 SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL,
950 initializer_list<SyntaxTreeNode>{},
951 subLineIdx + argument.subLineIdx
958 if (functionScriptIdx != SCRIPTIDX_NONE) {
959 syntaxTree.
type = scripts[functionScriptIdx].type == Script::TYPE_FUNCTION?SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_STACKLET;
967 if (method !=
nullptr) {
968 syntaxTree.
type = SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD;
975 _Console::printLine(getStatementInformation(statement, subLineIdx) +
": Unknown function/method: " +
string(methodName) +
"()");
977 parseErrors.push_back(getStatementInformation(statement, subLineIdx) +
": Unknown function/method: " +
string(methodName) +
"()");
985 bool MinitScript::setupFunctionAndStackletScriptIndices(
int scriptIdx) {
987 auto& script = scripts[scriptIdx];
988 auto statementIdx = STATEMENTIDX_FIRST;
990 for (
auto& syntaxTreeNode: script.syntaxTree) {
991 auto& statement = script.statements[statementIdx++];
993 if (setupFunctionAndStackletScriptIndices(syntaxTreeNode, statement) ==
false) {
1004 switch (syntaxTreeNode.
type) {
1005 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL:
1008 case(MinitScript::TYPE_ARRAY):
1009 case(MinitScript::TYPE_MAP):
1011 if (setupFunctionAndStackletScriptIndices(syntaxTreeNode.
value, statement, syntaxTreeNode.
subLineIdx) ==
false)
return false;
1015 case(MinitScript::TYPE_FUNCTION_ASSIGNMENT):
1018 auto functionScriptIdx = SCRIPTIDX_NONE;
1020 (functionScriptIdx = getFunctionScriptIdx(
function)) == SCRIPTIDX_NONE) {
1023 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1024 ": Function not found: " +
1028 parseErrors.push_back(
1029 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1030 ": Function not found: " +
1041 case(MinitScript::TYPE_STACKLET_ASSIGNMENT):
1044 auto stackletScriptIdx = SCRIPTIDX_NONE;
1046 (stackletScriptIdx = getFunctionScriptIdx(stacklet)) == SCRIPTIDX_NONE) {
1049 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1050 ": Stacklet not found" +
1054 parseErrors.push_back(
1055 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1056 ": Stacklet not found: " +
1073 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD:
1074 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:
1076 for (
auto& argument: syntaxTreeNode.
arguments) {
1077 if (setupFunctionAndStackletScriptIndices(argument, statement) ==
false)
return false;
1089 bool MinitScript::setupFunctionAndStackletScriptIndices(
Variable& variable,
const Statement& statement,
int subLineIdx) {
1094 if (arrayPointer ==
nullptr)
break;
1095 for (
auto arrayEntry: *arrayPointer) {
1096 if (setupFunctionAndStackletScriptIndices(*arrayEntry, statement, subLineIdx) ==
false)
return false;
1105 if (mapPointer ==
nullptr)
break;
1106 for (
auto& [mapKey, mapValue]: *mapPointer) {
1107 if (setupFunctionAndStackletScriptIndices(*mapValue, statement, subLineIdx) ==
false)
return false;
1112 case TYPE_FUNCTION_ASSIGNMENT:
1115 auto functionScriptIdx = SCRIPTIDX_NONE;
1117 (functionScriptIdx = getFunctionScriptIdx(
function)) == SCRIPTIDX_NONE) {
1120 getStatementInformation(statement, subLineIdx) +
1121 ": Function not found: " +
1125 parseErrors.push_back(
1126 getStatementInformation(statement, subLineIdx) +
1127 ": Function not found: " +
1138 case TYPE_STACKLET_ASSIGNMENT:
1141 auto stackletScriptIdx = SCRIPTIDX_NONE;
1143 (stackletScriptIdx = getFunctionScriptIdx(stacklet)) == SCRIPTIDX_NONE) {
1146 getStatementInformation(statement, subLineIdx) +
1147 ": Stacklet not found" +
1151 parseErrors.push_back(
1152 getStatementInformation(statement, subLineIdx) +
1153 ": Stacklet not found: " +
1170 int MinitScript::getStackletScopeScriptIdx(
int scriptIdx) {
1171 if (scriptIdx < 0 || scriptIdx >= scripts.size() ||
1172 scripts[scriptIdx].type != MinitScript::Script::TYPE_STACKLET) {
1173 return MinitScript::SCRIPTIDX_NONE;
1176 const auto& stackletScript = scripts[scriptIdx];
1177 const auto& stackletScopeName = stackletScript.arguments.size() == 1?stackletScript.arguments[0].name:string();
1178 if (stackletScopeName.empty() ==
true) {
1179 return MinitScript::SCRIPTIDX_NONE;
1182 for (
auto i = 0; i < scripts.size(); i++) {
1183 if (i == scriptIdx)
continue;
1184 const auto& scriptCandidate = scripts[i];
1185 if (scriptCandidate.type != MinitScript::Script::TYPE_FUNCTION && scriptCandidate.type != MinitScript::Script::TYPE_STACKLET)
continue;
1186 if (scriptCandidate.condition == stackletScopeName) {
1187 if (scriptCandidate.type == MinitScript::Script::TYPE_STACKLET)
return getStackletScopeScriptIdx(i);
else return i;
1191 return MinitScript::SCRIPTIDX_NONE;
1194 bool MinitScript::validateStacklets(
int scriptIdx) {
1196 const auto& script = scripts[scriptIdx];
1197 auto statementIdx = STATEMENTIDX_FIRST;
1199 for (
const auto& syntaxTreeNode: script.syntaxTree) {
1200 const auto& statement = script.statements[statementIdx++];
1202 if (validateStacklets(script.type == Script::TYPE_FUNCTION?scriptIdx:SCRIPTIDX_NONE, syntaxTreeNode, statement) ==
false) {
1211 bool MinitScript::validateStacklets(
const string&
function,
int scopeScriptIdx) {
1212 auto functionScriptIdx = getFunctionScriptIdx(
function);
1213 if (functionScriptIdx == SCRIPTIDX_NONE) {
1218 const auto& script = scripts[functionScriptIdx];
1219 auto statementIdx = STATEMENTIDX_FIRST;
1221 for (
const auto& syntaxTreeNode: script.syntaxTree) {
1222 const auto& statement = script.statements[statementIdx++];
1224 if (validateStacklets(scopeScriptIdx == MinitScript::SCRIPTIDX_NONE?functionScriptIdx:scopeScriptIdx, syntaxTreeNode, statement) ==
false) {
1234 switch (syntaxTreeNode.
type) {
1235 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL:
1239 if (syntaxTreeNode.
value.
getType() == MinitScript::TYPE_STACKLET_ASSIGNMENT) {
1241 string stackletName;
1242 auto stackletScriptIdx = SCRIPTIDX_NONE;
1244 (stackletScriptIdx = getFunctionScriptIdx(stackletName)) == SCRIPTIDX_NONE) {
1247 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1250 ": Stacklet not found"
1253 parseErrors.push_back(
1254 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1257 ": Stacklet not found"
1263 int stackletScopeScriptIdx = getStackletScopeScriptIdx(stackletScriptIdx);
1264 if (stackletScopeScriptIdx != scopeScriptIdx) {
1266 string scopeErrorMessage;
1267 if (stackletScopeScriptIdx == SCRIPTIDX_NONE) {
1268 scopeErrorMessage =
"Stacklet requires root scope";
1270 scopeErrorMessage =
"Stacklet requires scope of " + scripts[stackletScopeScriptIdx].condition +
"()";
1272 scopeErrorMessage+=
", but has scope of ";
1273 if (scopeScriptIdx == SCRIPTIDX_NONE) {
1274 scopeErrorMessage+=
"root scope";
1276 scopeErrorMessage+= scripts[scopeScriptIdx].condition +
"()";
1280 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1283 ": Stacklet scope invalid: " +
1287 parseErrors.push_back(
1288 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1291 ": Stacklet scope invalid" +
1298 if (validateStacklets(stackletName, scopeScriptIdx) ==
false)
return false;
1303 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD:
1305 for (
const auto& argument: syntaxTreeNode.
arguments) {
1306 if (validateStacklets(scopeScriptIdx, argument, statement) ==
false)
return false;
1311 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:
1313 for (
const auto& argument: syntaxTreeNode.
arguments) {
1314 if (validateStacklets(scopeScriptIdx, argument, statement) ==
false)
return false;
1325 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_STACKLET:
1329 auto stackletScriptIdx = syntaxTreeNode.
getScriptIdx();
1330 if (stackletName.empty() ==
true || stackletScriptIdx == SCRIPTIDX_NONE) {
1333 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1336 ": Stacklet not found"
1339 parseErrors.push_back(
1340 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1343 ": Stacklet not found"
1349 int stackletScopeScriptIdx = getStackletScopeScriptIdx(stackletScriptIdx);
1350 if (stackletScopeScriptIdx != scopeScriptIdx) {
1352 string scopeErrorMessage;
1353 if (stackletScopeScriptIdx == SCRIPTIDX_NONE) {
1354 scopeErrorMessage =
"Stacklet requires root scope";
1356 scopeErrorMessage =
"Stacklet requires scope of " + scripts[stackletScopeScriptIdx].condition +
"()";
1358 scopeErrorMessage+=
", but has scope of ";
1359 if (scopeScriptIdx == SCRIPTIDX_NONE) {
1360 scopeErrorMessage+=
"root scope";
1362 scopeErrorMessage+= scripts[scopeScriptIdx].condition +
"()";
1366 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1369 ": Stacklet scope invalid: " +
1373 parseErrors.push_back(
1374 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1377 ": Stacklet scope invalid" +
1395 bool MinitScript::validateCallable(
const string&
function) {
1396 auto functionScriptIdx = getFunctionScriptIdx(
function);
1397 if (functionScriptIdx == SCRIPTIDX_NONE) {
1402 const auto& script = scripts[functionScriptIdx];
1403 auto statementIdx = STATEMENTIDX_FIRST;
1405 for (
const auto& syntaxTreeNode: script.syntaxTree) {
1406 const auto& statement = script.statements[statementIdx++];
1408 if (validateCallable(syntaxTreeNode, statement) ==
false) {
1419 switch (syntaxTreeNode.
type) {
1420 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL:
1424 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD:
1427 if (contextFunctions.empty() ==
false) {
1430 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1435 parseErrors.push_back(
1436 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1445 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:
1447 for (
const auto& argument: syntaxTreeNode.
arguments) {
1448 if (validateCallable(argument, statement) ==
false)
return false;
1455 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_STACKLET:
1468 bool MinitScript::validateContextFunctions(
const string&
function, vector<string>& functionStack) {
1469 auto functionScriptIdx = getFunctionScriptIdx(
function);
1470 if (functionScriptIdx == SCRIPTIDX_NONE) {
1471 _Console::printLine(
"MinitScript::validateContextFunctions(): Function not found: " +
function);
1475 const auto& script = scripts[functionScriptIdx];
1476 auto statementIdx = STATEMENTIDX_FIRST;
1478 functionStack.push_back(script.condition);
1480 for (
const auto& syntaxTreeNode: script.syntaxTree) {
1481 const auto& statement = script.statements[statementIdx++];
1483 if (validateContextFunctions(syntaxTreeNode, functionStack, statement) ==
false) {
1489 functionStack.erase(functionStack.begin() + functionStack.size() - 1);
1494 bool MinitScript::validateContextFunctions(
const SyntaxTreeNode& syntaxTreeNode, vector<string>& functionStack,
const Statement& statement) {
1496 switch (syntaxTreeNode.
type) {
1497 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_LITERAL:
1501 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_METHOD:
1504 if (contextFunctions.empty() ==
false) {
1506 string contextFunctionsString;
1507 for (
const auto &contextFunction: contextFunctions) {
1508 if (contextFunctionsString.empty() ==
false) contextFunctionsString+=
", ";
1509 contextFunctionsString+= contextFunction +
"()";
1512 const auto& functionStackFunction = functionStack[0];
1513 if (find(contextFunctions.begin(), contextFunctions.end(), functionStackFunction) == contextFunctions.end()) {
1515 string contextFunctionsString;
1516 for (
const auto &contextFunction: contextFunctions) {
1517 if (contextFunctionsString.empty() ==
false) contextFunctionsString+=
", ";
1518 contextFunctionsString+= contextFunction +
"()";
1522 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1525 contextFunctionsString +
1526 ", but was called from " +
1527 functionStackFunction +
"()"
1530 parseErrors.push_back(
1531 getStatementInformation(statement, syntaxTreeNode.
subLineIdx) +
1534 contextFunctionsString +
1535 ", but was called from " +
1536 functionStackFunction +
"()"
1544 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_FUNCTION:
1545 case SyntaxTreeNode::SCRIPTSYNTAXTREENODE_EXECUTE_STACKLET:
1547 for (
const auto& argument: syntaxTreeNode.
arguments) {
1548 if (validateContextFunctions(argument, functionStack, statement) ==
false)
return false;
1562 void MinitScript::emit(
const string& condition) {
1564 if (isFunctionRunning() ==
true) {
1565 deferredEmit = condition;
1569 auto scriptIdxToStart = 0;
1570 for (
const auto& script: scripts) {
1571 auto conditionMet =
true;
1572 if (script.name.empty() ==
false && script.name == condition) {
1575 if (script.condition == condition) {
1581 if (scriptIdxToStart == scripts.size()) {
1582 scriptIdxToStart = SCRIPTIDX_NONE;
1587 getScriptState().running =
true;
1588 resetScriptExecutationState(scriptIdxToStart, STATEMACHINESTATE_NEXT_STATEMENT);
1593 void MinitScript::executeStateMachine() {
1594 while (
true ==
true) {
1596 auto& scriptState = getScriptState();
1599 if (scriptState.lastStateMachineState ==
nullptr || scriptState.state != scriptState.lastState) {
1600 scriptState.lastState = scriptState.state;
1601 scriptState.lastStateMachineState =
nullptr;
1602 auto stateMachineStateIt = stateMachineStates.find(scriptState.state);
1603 if (stateMachineStateIt != stateMachineStates.end()) {
1604 scriptState.lastStateMachineState = stateMachineStateIt->second;
1610 if (scriptState.lastStateMachineState !=
nullptr) {
1611 if (native ==
true && scriptState.state == STATEMACHINESTATE_NEXT_STATEMENT) {
1614 scriptState.lastStateMachineState->execute();
1624 if (native ==
true && isFunctionRunning() ==
false) {
1625 const auto& scriptState = getScriptState();
1628 if (enabledNamedConditions.empty() ==
false &&
1629 (timeEnabledConditionsCheckLast == TIME_NONE || now >= timeEnabledConditionsCheckLast + 100LL)) {
1630 auto scriptIdxToStart = determineNamedScriptIdxToStart();
1631 if (scriptIdxToStart != SCRIPTIDX_NONE && scriptIdxToStart != scriptState.scriptIdx) {
1633 resetScriptExecutationState(scriptIdxToStart, STATEMACHINESTATE_NEXT_STATEMENT);
1635 timeEnabledConditionsCheckLast = now;
1641 const auto& scriptState = getScriptState();
1642 if (scriptState.state != STATEMACHINESTATE_NEXT_STATEMENT || scriptState.running ==
false)
break;
1647 void MinitScript::execute() {
1648 const auto& scriptState = getScriptState();
1651 if (scriptState.running ==
false || scriptState.state == STATEMACHINESTATE_NONE)
return;
1655 if (isFunctionRunning() ==
false &&
1656 enabledNamedConditions.empty() ==
false &&
1657 (timeEnabledConditionsCheckLast == TIME_NONE || now >= timeEnabledConditionsCheckLast + 100LL)) {
1658 auto scriptIdxToStart = determineNamedScriptIdxToStart();
1659 if (scriptIdxToStart != SCRIPTIDX_NONE && scriptIdxToStart != scriptState.scriptIdx) {
1661 resetScriptExecutationState(scriptIdxToStart, STATEMACHINESTATE_NEXT_STATEMENT);
1663 timeEnabledConditionsCheckLast = now;
1667 executeStateMachine();
1670 tryGarbageCollection();
1673 bool MinitScript::getNextStatement(
const string& scriptCode,
int& i,
int& line,
string& statement) {
1674 string statementCode;
1675 vector<string> statementCodeLines;
1676 statementCodeLines.emplace_back();
1678 auto expectBracket =
false;
1679 auto canExpectStacklet =
false;
1680 auto inlineFunctionArguments =
false;
1681 auto bracketCount = 0;
1682 auto squareBracketCount = 0;
1683 auto curlyBracketCount = 0;
1685 auto expectRightArgument =
false;
1688 for (; i < scriptCode.size(); i++) {
1689 auto c = scriptCode[i];
1690 auto nc = i + 1 < scriptCode.size()?scriptCode[i + 1]:
'\0';
1692 if (c !=
'-' && c !=
'>' &&
1693 c !=
' ' && c !=
'\t' && c !=
'\n' && c !=
'\r') canExpectStacklet = c ==
',' || c ==
'(';
1695 if (hash ==
true && c !=
'\n') {
1698 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
1699 if (quote ==
'\0') {
1703 expectRightArgument =
false;
1707 statementCodeLines.back() += c;
1709 inlineFunctionArguments =
false;
1711 if (quote !=
'\0') {
1714 _Console::printLine(scriptFileName +
":" + to_string(line) +
": Newline within string literal is not allowed");
1715 parseErrors.push_back(scriptFileName +
":" + to_string(line) +
": Newline within string literal is not allowed");
1719 statementCodeLines.back() += c;
1724 inlineFunctionArguments =
false;
1725 expectRightArgument =
false;
1728 expectBracket =
false;
1730 statementCodeLines.back() += c;
1734 inlineFunctionArguments =
false;
1735 expectRightArgument =
false;
1739 statementCodeLines.back() += c;
1741 inlineFunctionArguments =
true;
1746 inlineFunctionArguments =
false;
1747 expectRightArgument =
false;
1749 squareBracketCount++;
1751 statementCodeLines.back() += c;
1755 inlineFunctionArguments =
false;
1756 expectRightArgument =
false;
1758 squareBracketCount--;
1760 statementCodeLines.back() += c;
1765 inlineFunctionArguments =
false;
1766 expectRightArgument =
false;
1768 curlyBracketCount++;
1770 statementCodeLines.back() += c;
1774 inlineFunctionArguments =
false;
1775 expectRightArgument =
false;
1777 curlyBracketCount--;
1779 statementCodeLines.back() += c;
1782 if (c ==
'#' && curlyBracketCount == 0 && squareBracketCount == 0) {
1796 (isOperatorChar(lc) ==
false && c ==
'!' && isOperatorChar(nc) ==
false) ||
1797 (isOperatorChar(lc) ==
false && c ==
'~' && isOperatorChar(nc) ==
false) ||
1798 (isOperatorChar(lc) ==
false && c ==
'*' && isOperatorChar(nc) ==
false) ||
1799 (isOperatorChar(lc) ==
false && c ==
'/' && isOperatorChar(nc) ==
false) ||
1800 (isOperatorChar(lc) ==
false && c ==
'%' && isOperatorChar(nc) ==
false) ||
1801 (isOperatorChar(lc) ==
false && c ==
'+' && isOperatorChar(nc) ==
false) ||
1802 (isOperatorChar(lc) ==
false && c ==
'-' && isOperatorChar(nc) ==
false) ||
1803 (isOperatorChar(lc) ==
false && c ==
'<' && isOperatorChar(nc) ==
false) ||
1804 (isOperatorChar(lc) ==
false && c ==
'>' && isOperatorChar(nc) ==
false) ||
1805 (isOperatorChar(lc) ==
false && c ==
'&' && isOperatorChar(nc) ==
false) ||
1806 (isOperatorChar(lc) ==
false && c ==
'^' && isOperatorChar(nc) ==
false) ||
1807 (isOperatorChar(lc) ==
false && c ==
'|' && isOperatorChar(nc) ==
false) ||
1808 (isOperatorChar(lc) ==
false && c ==
'=' && isOperatorChar(nc) ==
false) ||
1809 (isOperatorChar(llc) ==
false && lc ==
'<' && c ==
'=' && isOperatorChar(nc) ==
false) ||
1810 (isOperatorChar(llc) ==
false && lc ==
'>' && c ==
'=' && isOperatorChar(nc) ==
false) ||
1811 (isOperatorChar(llc) ==
false && lc ==
'=' && c ==
'=' && isOperatorChar(nc) ==
false) ||
1812 (isOperatorChar(llc) ==
false && lc ==
'!' && c ==
'=' && isOperatorChar(nc) ==
false) ||
1813 (isOperatorChar(llc) ==
false && lc ==
'&' && c ==
'&' && isOperatorChar(nc) ==
false) ||
1814 (isOperatorChar(llc) ==
false && lc ==
'|' && c ==
'|' && isOperatorChar(nc) ==
false)
1816 if (expectBracket ==
false && expectRightArgument ==
false && bracketCount == 0 && squareBracketCount == 0 && curlyBracketCount == 0) {
1817 expectRightArgument =
true;
1820 statementCodeLines.back() += c;
1822 if (lc ==
'-' && c ==
'>') {
1824 if (inlineFunctionArguments ==
false && canExpectStacklet ==
false) expectBracket =
true;
1826 expectRightArgument =
false;
1828 statementCodeLines.back() += c;
1830 if ((c ==
'\n' && ++line) || (hash ==
false && c ==
';')) {
1832 if (expectBracket ==
false && expectRightArgument ==
false && bracketCount == 0 && squareBracketCount == 0 && curlyBracketCount == 0)
break;
1838 statementCodeLines.emplace_back();
1840 statementCodeLines.back() += c;
1842 inlineFunctionArguments =
false;
1846 if (
_Character::isSpace(c) ==
false && c !=
'-' && nc !=
'>') inlineFunctionArguments =
false;
1848 statementCodeLines.back() += c;
1853 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
1859 for (
const auto& line: statementCodeLines) {
1861 statementCode+= trimmedLine;
1862 if (statementCode.empty() ==
false && lineIdx != statementCodeLines.size() - 1) statementCode+=
"\n";
1867 if (i == scriptCode.size() && scriptCode.back() !=
'\n') ++line;
1870 statement = statementCode;
1876 bool MinitScript::parseScriptInternal(
const string& scriptCode,
int lineIdxOffset) {
1878 auto scriptCount = scripts.size();
1879 auto haveScript =
false;
1880 auto lineIdx = LINE_FIRST;
1881 auto currentLineIdx = LINE_NONE;
1882 auto statementIdx = STATEMENTIDX_FIRST;
1884 enum Type { TYPE_FOR, TYPE_FOREACH, TYPE_IF, TYPE_ELSE, TYPE_ELSEIF, TYPE_SWITCH, TYPE_CASE, TYPE_DEFAULT };
1885 Block(Type type,
int statementIdx): type(type), statementIdx(statementIdx) {}
1889 vector<Block> blockStack;
1891 for (
auto i = 0; i < scriptCode.size(); i++) {
1893 currentLineIdx = lineIdx;
1896 string statementCode;
1897 if (getNextStatement(scriptCode, i, lineIdx, statementCode) ==
false) {
1899 scriptValid =
false;
1904 if (i == scriptCode.size() && scriptCode.back() !=
'\n') ++lineIdx;
1906 if (statementCode.empty() ==
true)
continue;
1909 if (haveScript ==
false) {
1911 if (statementCode ==
"function:" ||
1912 statementCode ==
"stacklet:" ||
1913 statementCode ==
"on:" ||
1914 statementCode ==
"on-enabled:" ||
1915 statementCode ==
"callable:") {
1919 for (; i < scriptCode.size(); i++) {
1920 string nextStatementCode;
1921 if (getNextStatement(scriptCode, i, lineIdx, nextStatementCode) ==
false) {
1923 scriptValid =
false;
1927 if (nextStatementCode.empty() ==
false) {
1928 statementCode+=
" " + nextStatementCode;
1938 if (statementCode.rfind(
":=") == string::npos) {
1940 auto gotName =
false;
1943 auto _lineIdx = lineIdx;
1944 auto _statementCode = statementCode;
1950 for (; i < scriptCode.size(); i++) {
1951 string nextStatementCode;
1952 if (getNextStatement(scriptCode, i, lineIdx, nextStatementCode) ==
false) {
1954 scriptValid =
false;
1958 if (nextStatementCode.empty() ==
false) {
1965 statementCode+=
" " + nextStatementCode;
1969 for (
auto j = 0; j < statementCode.size(); j++) {
1970 auto c = statementCode[j];
1972 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
1973 if (quote ==
'\0') {
1980 if (quote !=
'\0') {
1983 if (lc ==
':' && c ==
'=') {
1989 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
1992 if (gotName ==
true)
break;
1996 if (gotName ==
false) {
2000 statementCode = _statementCode;
2008 for (; i < scriptCode.size(); i++) {
2009 string nextStatementCode;
2010 if (getNextStatement(scriptCode, i, lineIdx, nextStatementCode) ==
false) {
2012 scriptValid =
false;
2015 if (nextStatementCode.empty() ==
false) {
2016 statementCode+=
" " + nextStatementCode;
2023 auto callable =
false;
2024 auto scriptType = Script::TYPE_NONE;
2031 scriptType = Script::TYPE_FUNCTION;
2034 if (scriptType != Script::TYPE_NONE) {
2038 vector<Script::Argument> arguments;
2041 if (scriptType == Script::TYPE_FUNCTION) {
2042 statement = callable ==
true?
2046 if (scriptType == Script::TYPE_STACKLET) {
2049 if (scriptType == Script::TYPE_ON)
2051 if (scriptType == Script::TYPE_ONENABLED)
2055 auto scriptLineNameSeparatorIdx =
2056 scriptType == Script::TYPE_FUNCTION?
2057 statement.rfind(
"function:"):
2058 (scriptType == Script::TYPE_STACKLET?
2059 statement.rfind(
"stacklet:"):
2060 statement.rfind(
":=")
2062 if (scriptLineNameSeparatorIdx != string::npos) {
2067 scriptLineNameSeparatorIdx +
2068 (scriptType == Script::TYPE_FUNCTION?
string(
"function").size():(scriptType == Script::TYPE_STACKLET?
string(
"stacklet").size():
string(
":=").size()))
2073 if (scriptType == Script::TYPE_FUNCTION ||
2074 scriptType == Script::TYPE_STACKLET) {
2075 auto leftBracketIdx = statement.find(
'(');
2076 auto rightBracketIdx = statement.find(
')');
2077 if (leftBracketIdx != string::npos || leftBracketIdx != string::npos) {
2078 if (leftBracketIdx == string::npos) {
2079 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Unbalanced bracket count");
2080 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Unbalanced bracket count");
2081 scriptValid =
false;
2084 if (rightBracketIdx == string::npos) {
2085 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Unbalanced bracket count");
2086 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Unbalanced bracket count");
2087 scriptValid =
false;
2093 for (
const auto& argumentName: argumentNamesTokenized) {
2095 auto reference =
false;
2096 auto privateScope =
false;
2099 privateScope =
true;
2106 if (scriptType == Script::TYPE_FUNCTION) {
2108 arguments.emplace_back(
2109 argumentNameTrimmed,
2114 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Invalid argument name: '" + argumentNameTrimmed +
"'");
2115 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Invalid argument name: '" + argumentNameTrimmed +
"'");
2116 scriptValid =
false;
2121 if (scriptType == Script::TYPE_STACKLET) {
2123 arguments.emplace_back(
2124 argumentNameTrimmed,
2129 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Invalid stacklet parent stacklet/function: '" + argumentNameTrimmed +
"'");
2130 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": " + (scriptType == Script::TYPE_FUNCTION?
"function":
"stacklet") +
": Invalid stacklet parent stacklet/function: '" + argumentNameTrimmed +
"'");
2131 scriptValid =
false;
2142 currentLineIdx + lineIdxOffset,
2148 auto conditionOrNameExecutable = doStatementPreProcessing(trimmedStatement, evaluateStatement);
2149 auto conditionOrName = trimmedStatement;
2151 statementIdx = STATEMENTIDX_FIRST;
2153 if (scriptType == Script::TYPE_FUNCTION || scriptType == Script::TYPE_STACKLET) {
2154 functions[conditionOrName] = scripts.size();
2158 scripts.emplace_back(
2160 currentLineIdx + lineIdxOffset,
2162 conditionOrNameExecutable,
2163 Statement(currentLineIdx + lineIdxOffset, statementIdx, conditionOrName, conditionOrNameExecutable, STATEMENTIDX_NONE),
2167 initializer_list<Statement>{},
2168 initializer_list<SyntaxTreeNode>{},
2173 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": expecting 'on:', 'on-enabled:', 'stacklet:', 'function:', 'callable:'");
2174 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": expecting 'on:', 'on-enabled:', 'stacklet:', 'function:', 'callable:'");
2175 scriptValid =
false;
2186 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": Unbalanced if/elseif/else/switch/case/default/forCondition/forTime/end");
2187 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": Unbalanced if/elseif/else/switch/case/default/forCondition/forTime/end");
2188 scriptValid =
false;
2194 if (statementCode ==
"end") {
2195 if (blockStack.empty() ==
false) {
2196 auto block = blockStack.back();
2197 blockStack.erase(blockStack.begin() + blockStack.size() - 1);
2198 switch(block.type) {
2199 case Block::TYPE_FOR:
2200 case Block::TYPE_FOREACH:
2202 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, block.statementIdx);
2203 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2206 case Block::TYPE_IF:
2208 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2209 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2212 case Block::TYPE_ELSE:
2214 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2215 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2218 case Block::TYPE_ELSEIF:
2220 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2221 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2224 case Block::TYPE_SWITCH:
2226 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2229 case Block::TYPE_CASE:
2231 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size() + 1;
2232 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2235 case Block::TYPE_DEFAULT:
2237 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size() + 1;
2238 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2243 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2247 if (statementCode ==
"else") {
2248 if (blockStack.empty() ==
false) {
2249 auto block = blockStack.back();
2250 blockStack.erase(blockStack.begin() + blockStack.size() - 1);
2251 switch(block.type) {
2252 case Block::TYPE_IF:
2254 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2255 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2258 case Block::TYPE_ELSEIF:
2260 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2261 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, statementCode, STATEMENTIDX_NONE);
2265 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": else without if/elseif");
2266 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": else without if/elseif");
2267 scriptValid =
false;
2270 blockStack.emplace_back(
2275 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": else without if");
2276 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": else without if");
2277 scriptValid =
false;
2283 currentLineIdx + lineIdxOffset,
2289 auto executableStatement = doStatementPreProcessing(statementCode, elseIfStatement);
2290 if (blockStack.empty() ==
false) {
2291 auto block = blockStack.back();
2292 blockStack.erase(blockStack.begin() + blockStack.size() - 1);
2293 switch(block.type) {
2294 case Block::TYPE_IF:
2296 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2297 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, executableStatement, STATEMENTIDX_NONE);
2300 case Block::TYPE_ELSEIF:
2302 scripts.back().statements[block.statementIdx].gotoStatementIdx = scripts.back().statements.size();
2303 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx, statementCode, executableStatement, STATEMENTIDX_NONE);
2307 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": elseif without if");
2308 parseErrors.push_back(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": elseif without if");
2309 scriptValid =
false;
2312 blockStack.emplace_back(
2317 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": elseif without if");
2318 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": elseif without if");
2319 scriptValid =
false;
2325 currentLineIdx + lineIdxOffset,
2333 string_view forMethodName;
2334 vector<ParserArgument> forArguments;
2335 string accessObjectMemberStatement;
2336 string executableStatement = doStatementPreProcessing(statementCode, generatedStatement);
2338 if (parseStatement(executableStatement, forMethodName, forArguments, generatedStatement, accessObjectMemberStatement) ==
true &&
2339 forArguments.size() == 3) {
2341 string initializeStatement = string(forArguments[0].argument);
2342 scripts.back().statements.emplace_back(currentLineIdx + lineIdxOffset, statementIdx++, statementCode, initializeStatement, STATEMENTIDX_NONE);
2344 blockStack.emplace_back(
2349 statementCode =
"forCondition(" + string(forArguments[1].argument) +
", -> { " + string(forArguments[2].argument) +
" })";
2351 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": Invalid for statement");
2352 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": Invalid for statement");
2353 scriptValid =
false;
2358 if (
_StringTools::regexMatch(regexStatementCode,
"^forEach[\\s]*\\([\\s]*(&?\\$[a-zA-Z0-9_]+)[\\s]*\\in[\\s]*((\\$[a-zA-Z0-9_]+)|(\\[.*\\])|(\\{.*\\}))[\\s]*\\)$", &matches) ==
true) {
2359 auto iterationDepth = 0;
2360 for (
const auto& block: blockStack) {
2361 if (block.type == Block::TYPE_FOREACH) iterationDepth++;
2364 auto entryReference =
false;
2365 auto entryVariable = matches[1].str();
2367 entryReference =
true;
2370 auto containerByInitializer =
false;
2371 auto containerVariable = matches[2].str();
2372 string containerInitializer;
2374 containerByInitializer =
true;
2375 containerInitializer = containerVariable;
2376 containerVariable = string(
"$___cv_" + to_string(iterationDepth));
2378 auto initializationStackletVariable = string(
"$___is_" + to_string(iterationDepth));
2379 auto containerVariableType = string(
"$___vt_" + to_string(iterationDepth));
2380 auto iterationVariable = string(
"$___it_" + to_string(iterationDepth));
2381 auto entryVariableBackup = string(
"$___evb_" + to_string(iterationDepth));
2382 auto containerArrayVariable = string(
"$___cav_" + to_string(iterationDepth));
2383 auto containerArrayVariableBackup = string(
"$___cavb_" + to_string(iterationDepth));
2384 string iterationUpdate =
2385 entryReference ==
true?
2386 "setVariableReference(\"" + entryVariable +
"\", " + containerArrayVariable +
"[" + iterationVariable +
"])":
2387 entryVariable +
" = " + containerArrayVariable +
"[" + iterationVariable +
"]";
2389 string initialization =
2390 initializationStackletVariable +
" = -> { " +
2391 "if (script.isNative() == true); " +
2392 "setVariableReference(\"" + containerArrayVariableBackup +
"\", " + containerArrayVariable +
"); " +
2393 "setVariableReference(\"" + entryVariableBackup +
"\", " + entryVariable +
"); " +
2395 containerVariableType +
" = getType(" + containerVariable +
"); " +
2396 "if (" + containerVariableType +
" == \"Array\"); " +
2397 "setVariableReference(\"" + containerArrayVariable +
"\", " + containerVariable +
"); " +
2398 "elseif (" + containerVariableType +
" == \"Set\"); " +
2399 containerArrayVariable +
" = Set::getKeys(" + containerVariable +
"); " +
2401 "console.printLine(\"forEach() expects array or set as container, but got \" + String::toLowerCase(getType(" + containerVariable +
"))); " +
2402 "script.emit(\"error\"); " +
2404 iterationVariable +
" = 0; " +
2405 "if (" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
")); " +
2406 iterationUpdate +
"; " +
2410 if (containerByInitializer ==
true) {
2411 scripts.back().statements.emplace_back(
2412 currentLineIdx + lineIdxOffset,
2415 doStatementPreProcessing(containerVariable +
" = " + containerInitializer, generatedStatement),
2419 scripts.back().statements.emplace_back(
2420 currentLineIdx + lineIdxOffset,
2423 doStatementPreProcessing(initialization, generatedStatement),
2426 scripts.back().statements.emplace_back(
2427 currentLineIdx + lineIdxOffset,
2430 "internal.script.callStacklet(" + initializationStackletVariable +
")",
2433 blockStack.emplace_back(
2434 Block::TYPE_FOREACH,
2439 "forCondition(" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
"), " +
2441 iterationVariable +
"++" +
"; " +
2442 "if (" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
")); " +
2443 iterationUpdate +
"; " +
2445 "if (script.isNative() == true); " +
2446 "setVariableReference(\"" + containerArrayVariable +
"\", " + containerArrayVariableBackup +
"); " +
2447 "setVariableReference(\"" + entryVariable +
"\", " + entryVariableBackup +
"); " +
2449 "unsetVariableReference(\"" + containerArrayVariable +
"\"); " +
2450 "unsetVariableReference(\"" + entryVariable +
"\"); " +
2452 "setVariable(\"" + containerArrayVariable +
"\", $$.___ARRAY); " +
2453 "setVariable(\"" + entryVariable +
"\", $$.___NULL); " +
2454 (containerByInitializer ==
true?
"setVariable(\"" + containerVariable +
"\", $$.___ARRAY); ":
"") +
2459 if (
_StringTools::regexMatch(regexStatementCode,
"^forEach[\\s]*\\([\\s]*(\\$[a-zA-Z0-9_]+)[\\s]*,[\\s]*(&?\\$[a-zA-Z0-9_]+)[\\s]*\\in[\\s]*((\\$[a-zA-Z0-9_]+)|(\\[.*\\])|(\\{.*\\}))[\\s]*\\)$", &matches) ==
true) {
2460 auto iterationDepth = 0;
2461 for (
const auto& block: blockStack) {
2462 if (block.type == Block::TYPE_FOREACH) iterationDepth++;
2465 auto entryKeyVariable = matches[1].str();
2466 auto entryValueReference =
false;
2467 auto entryValueVariable = matches[2].str();
2469 entryValueReference =
true;
2472 auto containerByInitializer =
false;
2473 auto containerVariable = matches[3].str();
2474 string containerInitializer;
2476 containerByInitializer =
true;
2477 containerInitializer = containerVariable;
2478 containerVariable = string(
"$___cv_" + to_string(iterationDepth));
2480 auto initializationStackletVariable = string(
"$___is_" + to_string(iterationDepth));
2481 auto containerVariableType = string(
"$___vt_" + to_string(iterationDepth));
2482 auto iterationVariable = string(
"$___it_" + to_string(iterationDepth));
2483 auto entryValueVariableBackup = string(
"$___evb_" + to_string(iterationDepth));
2484 auto containerArrayVariable = string(
"$___cav_" + to_string(iterationDepth));
2485 auto containerArrayVariableBackup = string(
"$___cavb_" + to_string(iterationDepth));
2486 string iterationUpdate =
2487 entryKeyVariable +
" = " + containerArrayVariable +
"[" + iterationVariable +
"]; " +
2488 (entryValueReference ==
true?
2489 "setVariableReference(\"" + entryValueVariable +
"\", Map::getReference(" + containerVariable +
", " + entryKeyVariable +
"))":
2490 entryValueVariable +
" = Map::get(" + containerVariable +
", " + entryKeyVariable +
")"
2493 string initialization =
2494 initializationStackletVariable +
" = -> { " +
2495 "if (script.isNative() == true); " +
2496 "setVariableReference(\"" + containerArrayVariable +
"\", " + containerArrayVariableBackup +
"); " +
2497 "setVariableReference(\"" + entryValueVariable +
"\", " + entryValueVariableBackup +
"); " +
2499 containerVariableType +
" = getType(" + containerVariable +
"); " +
2500 "if (" + containerVariableType +
" == \"Map\"); " +
2501 containerArrayVariable +
" = Map::getKeys(" + containerVariable +
"); " +
2503 "console.printLine(\"forEach() expects map as container, but got \" + String::toLowerCase(getType(" + containerVariable +
"))); " +
2504 "script.emit(\"error\"); " +
2506 iterationVariable +
" = 0; " +
2507 "if (" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
")); " +
2508 iterationUpdate +
"; " +
2512 if (containerByInitializer ==
true) {
2513 scripts.back().statements.emplace_back(
2514 currentLineIdx + lineIdxOffset,
2517 doStatementPreProcessing(containerVariable +
" = " + containerInitializer, generatedStatement),
2521 scripts.back().statements.emplace_back(
2522 currentLineIdx + lineIdxOffset,
2525 doStatementPreProcessing(initialization, generatedStatement),
2528 scripts.back().statements.emplace_back(
2529 currentLineIdx + lineIdxOffset,
2532 "internal.script.callStacklet(" + initializationStackletVariable +
")",
2535 blockStack.emplace_back(
2536 Block::TYPE_FOREACH,
2541 "forCondition(" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
"), " +
2543 iterationVariable +
"++" +
"; " +
2544 "if (" + iterationVariable +
" < Array::getSize(" + containerArrayVariable +
")); " +
2545 iterationUpdate +
"; " +
2547 "if (script.isNative() == true); " +
2548 "setVariableReference(\"" + containerArrayVariable +
"\", " + containerArrayVariableBackup +
"); " +
2549 "setVariableReference(\"" + entryValueVariable +
"\", " + entryValueVariableBackup +
"); " +
2551 "unsetVariableReference(\"" + containerArrayVariable +
"\"); " +
2552 "unsetVariableReference(\"" + entryValueVariable +
"\"); " +
2554 "setVariable(\"" + containerArrayVariable +
"\", $$.___ARRAY); " +
2555 "setVariable(\"" + entryKeyVariable +
"\", $$.___NULL); "
2556 "setVariable(\"" + entryValueVariable +
"\", $$.___NULL); " +
2557 (containerByInitializer ==
true?
"setVariable(\"" + containerVariable +
"\", $$.___ARRAY); ":
"") +
2562 _Console::printLine(scriptFileName +
":" + to_string(currentLineIdx + lineIdxOffset) +
": Invalid forEach statement");
2563 parseErrors.push_back(to_string(currentLineIdx + lineIdxOffset) +
": Invalid forEach statement");
2564 scriptValid =
false;
2569 blockStack.emplace_back(
2575 blockStack.emplace_back(
2581 blockStack.emplace_back(
2587 blockStack.emplace_back(
2593 blockStack.emplace_back(
2594 Block::TYPE_DEFAULT,
2598 scripts.back().statements.emplace_back(
2599 currentLineIdx + lineIdxOffset,
2602 doStatementPreProcessing(statementCode, generatedStatement),
2612 if (scriptValid ==
true && blockStack.empty() ==
false) {
2613 _Console::printLine(scriptFileName +
": Unbalanced if/elseif/else/switch/case/default/forCondition/forTime/end");
2614 parseErrors.push_back(
"Unbalanced if/elseif/else/switch/case/default/forCondition/forTime/end");
2615 scriptValid =
false;
2620 for (
auto scriptIdx = scriptCount; scriptIdx < scripts.size(); scriptIdx++) {
2621 auto& script = scripts[scriptIdx];
2623 if (script.emitCondition ==
false && script.executableCondition.empty() ==
false) {
2625 vector<ParserArgument> arguments;
2626 string accessObjectMemberStatement;
2627 if (parseStatement(script.executableCondition, method, arguments, script.conditionStatement, accessObjectMemberStatement) ==
false) {
2628 scriptValid =
false;
2631 if (createStatementSyntaxTree(SCRIPTIDX_NONE, method, arguments, script.conditionStatement, script.conditionSyntaxTree) ==
false) {
2632 scriptValid =
false;
2637 for (
auto statementIdx = STATEMENTIDX_FIRST; statementIdx < script.statements.size(); statementIdx++) {
2638 const auto& statement = script.statements[statementIdx];
2639 script.syntaxTree.emplace_back();
2640 auto& syntaxTree = script.syntaxTree.back();
2641 string_view methodName;
2642 vector<ParserArgument> arguments;
2643 string accessObjectMemberStatement;
2644 if (parseStatement(statement.executableStatement, methodName, arguments, statement, accessObjectMemberStatement) ==
false) {
2645 scriptValid =
false;
2648 if (createStatementSyntaxTree(scriptIdx, methodName, arguments, statement, syntaxTree) ==
false) {
2649 scriptValid =
false;
2658 void MinitScript::parseScript(
const string& pathName,
const string& fileName,
bool nativeOnly) {
2661 scriptPathName = pathName;
2662 scriptFileName = fileName;
2665 for (
const auto& [methodName, method]: methods)
delete method;
2666 for (
const auto& [stateMachineStateId, stateMachineState]: stateMachineStates)
delete stateMachineState;
2668 stateMachineStates.clear();
2669 while (scriptStateStack.empty() ==
false) popScriptState();
2673 resetScriptExecutationState(SCRIPTIDX_NONE, STATEMACHINESTATE_WAIT_FOR_CONDITION);
2677 if (native ==
false || nativeOnly ==
false) {
2681 _Console::printLine(scriptPathName +
"/" + scriptFileName +
": An error occurred: " + fse.what());
2685 parseErrors.push_back(
"An error occurred: " +
string(fse.what()));
2694 if (native ==
true) {
2695 if (nativeOnly ==
true || scriptHash == nativeHash) {
2696 scripts = nativeScripts;
2697 registerStateMachineStates();
2699 registerVariables();
2703 _Console::printLine(scriptPathName +
"/" + scriptFileName +
": Script has changed. Script will be run in interpreted mode. Retranspile and recompile your script if you want to run it natively.");
2707 nativeHash = scriptHash;
2711 registerStateMachineStates();
2713 registerVariables();
2716 if (parseScriptInternal(scriptCode) ==
false)
return;
2721 auto deferredInlineScriptCodesCopy = deferredInlineScriptCodes;
2722 deferredInlineScriptCodes.clear();
2723 for (
const auto& functionScriptCodePair: deferredInlineScriptCodesCopy) {
2724 parseScriptInternal(functionScriptCodePair.second, functionScriptCodePair.first);
2726 }
while (deferredInlineScriptCodes.empty() ==
false);
2728 for (
auto scriptIdx = 0; scriptIdx < scripts.size(); scriptIdx++) {
2730 if (setupFunctionAndStackletScriptIndices(scriptIdx) ==
false) {
2731 scriptValid =
false;
2736 if (scriptValid ==
true) {
2737 for (
auto scriptIdx = 0; scriptIdx < scripts.size(); scriptIdx++) {
2738 const auto& script = scripts[scriptIdx];
2740 if (script.type == MinitScript::Script::TYPE_STACKLET) {
2742 if (script.arguments.empty())
continue;
2744 if (script.arguments.size() != 1) {
2745 _Console::printLine(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: only none(for root scope) or one argument is allowed, which defines a function/stacklet as stacklet scope");
2746 parseErrors.push_back(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: only none(for root scope) or one argument is allowed, which defines a function/stacklet as stacklet scope");
2747 scriptValid =
false;
2751 auto stackletScopeScriptIdx = getFunctionScriptIdx(script.arguments[0].name);
2753 if (stackletScopeScriptIdx == SCRIPTIDX_NONE) {
2754 _Console::printLine(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: scope function/stacklet not found: " + script.arguments[0].name);
2755 parseErrors.push_back(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: scope function/stacklet not found: " + script.arguments[0].name);
2756 scriptValid =
false;
2760 if (stackletScopeScriptIdx == scriptIdx) {
2761 _Console::printLine(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: scope function/stacklet can not be the stacklet itself");
2762 parseErrors.push_back(scriptFileName +
": Stacklet: " + script.condition +
": invalid arguments: scope function/stacklet can not be the stacklet itself");
2763 scriptValid =
false;
2768 if (script.type == MinitScript::Script::TYPE_FUNCTION ||
2769 script.type == MinitScript::Script::TYPE_ON ||
2770 script.type == MinitScript::Script::TYPE_ONENABLED) {
2772 if (validateStacklets(scriptIdx) ==
false) {
2773 scriptValid =
false;
2778 if (script.type == MinitScript::Script::TYPE_FUNCTION) {
2780 if (script.callable ==
true) {
2782 if (validateCallable(script.condition) ==
false) {
2783 scriptValid =
false;
2788 vector<string> functionStack;
2790 if (validateContextFunctions(script.condition, functionStack) ==
false) {
2791 scriptValid =
false;
2800 auto haveErrorScript =
false;
2801 for (
const auto& script: scripts) {
2802 if (script.type == Script::TYPE_ONENABLED) {
2805 if (script.condition ==
"error") {
2806 haveErrorScript =
true;
2809 if (haveErrorScript ==
false) {
2810 _Console::printLine(scriptPathName +
"/" + scriptFileName +
": Script needs to define an error condition");
2811 parseErrors.push_back(
"Script needs to define an error condition");
2812 scriptValid =
false;
2820 void MinitScript::startScript() {
2821 if (VERBOSE ==
true)
_Console::printLine(
"MinitScript::startScript(): '" + scriptFileName +
": Starting script.");
2822 if (scriptValid ==
false) {
2826 auto& scriptState = getScriptState();
2827 for (
const auto& [variableName, variable]: scriptState.variables)
delete variable;
2828 scriptState.variables.clear();
2829 scriptState.running =
true;
2830 registerVariables();
2832 if (hasCondition(
"initialize") ==
true) emit(
"initialize");
2835 int MinitScript::determineScriptIdxToStart() {
2837 auto nothingScriptIdx = SCRIPTIDX_NONE;
2839 for (
const auto& script: scripts) {
2840 if (script.type != Script::TYPE_ON) {
2843 if (script.emitCondition ==
true && script.condition ==
"nothing") {
2844 nothingScriptIdx = scriptIdx;
2847 if (script.emitCondition ==
true) {
2850 auto conditionMet =
true;
2852 if (evaluateInternal(script.condition, script.executableCondition, returnValue) ==
true) {
2853 auto returnValueBoolValue =
false;
2854 if (returnValue.
getBooleanValue(returnValueBoolValue,
false) ==
false) {
2855 _Console::printLine(
"MinitScript::determineScriptIdxToStart(): " + script.condition +
": Expecting boolean return value, but got: " + returnValue.
getAsString());
2856 conditionMet =
false;
2858 if (returnValueBoolValue ==
false) {
2859 conditionMet =
false;
2862 _Console::printLine(
"MinitScript::determineScriptIdxToStart(): " + scriptFileName +
":" + to_string(script.line) +
": " + script.condition +
": Parse error");
2864 if (conditionMet ==
false) {
2865 if (VERBOSE ==
true) {
2866 _Console::print(
"MinitScript::determineScriptIdxToStart(): " + script.condition +
": FAILED");
2869 if (VERBOSE ==
true) {
2870 _Console::print(
"MinitScript::determineScriptIdxToStart(): " + script.condition +
": OK");
2877 return nothingScriptIdx;
2880 int MinitScript::determineNamedScriptIdxToStart() {
2881 if (VERBOSE ==
true)
_Console::printLine(
"MinitScript::determineNamedScriptIdxToStart()");
2883 const auto& scriptState = getScriptState();
2884 for (
const auto& enabledConditionName: enabledNamedConditions) {
2886 for (
const auto& script: scripts) {
2887 if (script.type != Script::TYPE_ONENABLED ||
2888 script.name != enabledConditionName) {
2891 auto conditionMet =
true;
2893 if (evaluateInternal(script.condition, script.executableCondition, returnValue) ==
true) {
2894 auto returnValueBoolValue =
false;
2895 if (returnValue.
getBooleanValue(returnValueBoolValue,
false) ==
false) {
2896 _Console::printLine(
"MinitScript::determineNamedScriptIdxToStart(): " + script.condition +
": Expecting boolean return value, but got: " + returnValue.
getAsString());
2897 conditionMet =
false;
2899 if (returnValueBoolValue ==
false) {
2900 conditionMet =
false;
2903 _Console::printLine(
"MinitScript::determineNamedScriptIdxToStart(): " + scriptFileName +
":" + to_string(script.line) +
": " + script.condition +
": Parse error");
2905 if (conditionMet ==
false) {
2906 if (VERBOSE ==
true) {
2907 _Console::print(
"MinitScript::determineNamedScriptIdxToStart(): " + script.condition +
": FAILED");
2910 if (VERBOSE ==
true) {
2911 _Console::print(
"MinitScript::determineNamedScriptIdxToStart(): " + script.condition +
": OK");
2919 return SCRIPTIDX_NONE;
2922 const string MinitScript::doStatementPreProcessing(
const string& processedStatement,
const Statement& statement) {
2923 auto preprocessedStatement = processedStatement;
2925 struct StatementOperator {
2926 int idx { OPERATORIDX_NONE };
2928 string invalidOperator;
2931 auto trimArgument = [](
const string& argument) ->
const string {
2932 auto leftNewLineCount = 0;
2933 for (
auto i = 0; i < argument.size(); i++) {
2934 auto c = argument[i];
2942 auto rightNewLineCount = 0;
2943 for (
int i = argument.size() - 1; i >= 0; i--) {
2944 auto c = argument[i];
2946 rightNewLineCount++;
2959 auto findLeftArgument = [&](
const string& statement,
int position,
int& length,
string& brackets) ->
const string {
2961 auto bracketCount = 0;
2962 auto squareBracketCount = 0;
2963 auto curlyBracketCount = 0;
2968 for (
int i = position; i >= 0; i--) {
2969 auto c = statement[i];
2970 auto lc = i > 0?statement[i - 1]:
'\0';
2971 if (lc ==
'\\' && c ==
'\\') lc =
'\0';
2973 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
2974 if (quote ==
'\0') {
2980 argument = c + argument;
2982 if (quote ==
'\0') {
2985 argument = c + argument;
2988 squareBracketCount++;
2989 argument = c + argument;
2992 curlyBracketCount++;
2993 argument = c + argument;
2997 if (bracketCount < 0) {
2999 return trimArgument(argument);
3001 argument = c + argument;
3004 squareBracketCount--;
3005 if (squareBracketCount < 0) {
3007 return trimArgument(argument);
3009 argument = c + argument;
3012 curlyBracketCount--;
3013 if (curlyBracketCount < 0) {
3015 return trimArgument(argument);
3017 argument = c + argument;
3019 if (squareBracketCount == 0 && curlyBracketCount == 0 && c ==
',') {
3020 if (bracketCount == 0)
return trimArgument(argument);
3021 argument = c + argument;
3023 argument = c + argument;
3026 if (quote !=
'\0') {
3027 argument = c + argument;
3031 return trimArgument(argument);
3034 auto findRightArgument = [&](
const string& statement,
int position,
int& length,
string& brackets) ->
const string {
3036 auto bracketCount = 0;
3037 auto squareBracketCount = 0;
3038 auto curlyBracketCount = 0;
3043 for (
auto i = position; i < statement.size(); i++) {
3044 auto c = statement[i];
3046 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
3047 if (quote ==
'\0') {
3056 if (quote ==
'\0') {
3062 squareBracketCount++;
3066 curlyBracketCount++;
3071 if (bracketCount < 0) {
3073 return trimArgument(argument);
3078 squareBracketCount--;
3082 if (squareBracketCount < 0) {
3084 return trimArgument(argument);
3090 curlyBracketCount--;
3091 if (curlyBracketCount < 0) {
3093 return trimArgument(argument);
3097 if (squareBracketCount == 0 && curlyBracketCount == 0 && c ==
',') {
3098 if (bracketCount == 0)
return trimArgument(argument);
3100 if (argument.empty() ==
true && (c ==
' ' || c ==
'\t')) {
3107 if (argument.empty() ==
true && (c ==
' ' || c ==
'\t')) {
3114 if (quote !=
'\0') {
3119 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
3122 return trimArgument(argument);
3125 auto viewIsLamdaFunction = [](
const string_view& candidate) ->
bool {
3126 if (candidate.empty() ==
true)
return false;
3130 if (candidate[i++] !=
'(')
return false;
3133 if (i >= candidate.size())
return false;
3135 auto argumentStartIdx = string::npos;
3136 auto argumentEndIdx = string::npos;
3138 for (; i < candidate.size(); i++) {
3139 auto c = candidate[i];
3141 if (argumentStartIdx == string::npos) {
3142 argumentStartIdx = i;
3148 if (argumentStartIdx == string::npos) {
3149 argumentStartIdx = i;
3151 if (argumentStartIdx == i - 1 && candidate[argumentStartIdx] ==
'&') {
3157 if (c ==
',' || c ==
')') {
3158 if (argumentEndIdx == string::npos) {
3159 if (argumentStartIdx != string::npos) {
3163 argumentStartIdx = string::npos;
3164 argumentEndIdx = string::npos;
3178 if (i >= candidate.size())
return false;
3181 if (i >= candidate.size())
return false;
3183 if (candidate[i++] !=
'-')
return false;
3185 if (i >= candidate.size())
return false;
3187 if (candidate[i++] !=
'>')
return false;
3190 if (i >= candidate.size())
return false;
3192 if (candidate[i++] !=
'{')
return false;
3197 auto getNextStatementOperator = [&](
const string& processedStatement, StatementOperator& nextOperator,
const Statement& statement) {
3198 bool lamdaFunctionDeclaration =
false;
3199 auto curlyBracketCount = 0;
3200 auto bracketCount = 0;
3203 for (
auto i = 0; i < processedStatement.size(); i++) {
3204 auto c = processedStatement[i];
3205 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
3206 if (quote ==
'\0') {
3213 if (quote ==
'\0') {
3216 string_view lamdaFunctionCandidate(&processedStatement[i], processedStatement.size() - i);
3217 if (viewIsLamdaFunction(lamdaFunctionCandidate) ==
true) lamdaFunctionDeclaration =
true;
3221 if (lamdaFunctionDeclaration ==
true) lamdaFunctionDeclaration =
false;
3225 curlyBracketCount++;
3228 curlyBracketCount--;
3230 if (curlyBracketCount == 0 && lamdaFunctionDeclaration ==
false) {
3233 string operatorCandidate;
3234 for (
int j = i - 1; j >= 0; j--) {
3235 if (isOperatorChar(processedStatement[j]) ==
false)
break;
3236 operatorCandidate = processedStatement[j] + operatorCandidate;
3238 for (
auto j = i; j < processedStatement.size(); j++) {
3239 if (isOperatorChar(processedStatement[j]) ==
false)
break;
3240 operatorCandidate = operatorCandidate + processedStatement[j];
3243 if (operatorCandidate.empty() ==
false && operatorCandidate !=
"->") {
3245 if (isOperator(operatorCandidate) ==
false) {
3246 nextOperator.idx = i;
3247 nextOperator.operator_ = OPERATOR_NONE;
3248 nextOperator.invalidOperator = operatorCandidate;
3252 for (
int j = OPERATOR_NONE + 1; j < OPERATOR_MAX; j++) {
3253 auto priorizedOperator =
static_cast<Operator>(j);
3254 string operatorCandidate;
3255 auto operatorString = getOperatorAsString(priorizedOperator);
3256 if (operatorString.size() == 1) operatorCandidate+= processedStatement[i];
3257 if (operatorString.size() == 2 && i + 1 < processedStatement.size()) {
3258 operatorCandidate+= processedStatement[i];
3259 operatorCandidate+= processedStatement[i + 1];
3261 if (operatorString == operatorCandidate && (nextOperator.idx == OPERATORIDX_NONE || priorizedOperator > nextOperator.operator_)) {
3262 auto isMemberAccessOrAssignmentOperator = [](
const string& candidate) {
return candidate ==
"->"; };
3263 if (operatorString.size() == 1 &&
3265 isOperatorChar(processedStatement[i - 1]) ==
true &&
3266 (isMemberAccessOrAssignmentOperator(processedStatement[i - 1] + operatorString) ==
true ||
3267 isOperator(processedStatement[i - 1] + operatorString) ==
true)) {
3270 if (operatorString.size() == 1 &&
3271 i + 1 < processedStatement.size() &&
3272 isOperatorChar(processedStatement[i + 1]) ==
true &&
3273 (isMemberAccessOrAssignmentOperator(operatorString + processedStatement[i + 1]) ==
true ||
3274 isOperator(operatorString + processedStatement[i + 1]) ==
true)) {
3277 if (operatorString.size() == 2 &&
3279 isOperatorChar(processedStatement[i - 1]) ==
true) {
3282 if (operatorString.size() == 2 &&
3283 i + 2 < processedStatement.size() &&
3284 isOperatorChar(processedStatement[i + 2]) ==
true) {
3287 if (priorizedOperator == OPERATOR_SUBTRACTION) {
3288 string leftArgumentBrackets;
3289 auto leftArgumentLeft = 0;
3290 auto leftArgument = findLeftArgument(processedStatement, i - 1, leftArgumentLeft, leftArgumentBrackets);
3291 if (leftArgument.length() == 0)
continue;
3293 nextOperator.idx = i;
3294 nextOperator.operator_ = priorizedOperator;
3299 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
3303 if (bracketCount > 0) {
3308 return nextOperator.idx != OPERATORIDX_NONE;
3311 auto encodeOperatorString = [](
const string& operatorString) -> int64_t {
3312 int64_t result = 0ll;
3313 if (operatorString.size() >= 1) result+=
static_cast<int64_t
>(operatorString[0]);
3314 if (operatorString.size() >= 2) result+=
static_cast<int64_t
>(operatorString[1]) << 8;
3318 StatementOperator nextOperator;
3319 while (getNextStatementOperator(preprocessedStatement, nextOperator, statement) ==
true) {
3321 if (nextOperator.invalidOperator.empty() ==
false) {
3322 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": Invalid operator: " + nextOperator.invalidOperator);
3323 scriptValid =
false;
3324 return preprocessedStatement;
3327 Method* method {
nullptr };
3328 Method* prefixOperatorMethod {
nullptr };
3329 Method* postfixOperatorMethod {
nullptr };
3333 method = getOperatorMethod(nextOperator.operator_);
3334 if (method ==
nullptr) {
3335 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": No operator method found");
3336 scriptValid =
false;
3337 return preprocessedStatement;
3340 postfixOperatorMethod = method;
3343 if (method->getOperator() == OPERATOR_POSTFIX_INCREMENT ||
3344 method->getOperator() == OPERATOR_PREFIX_INCREMENT) {
3345 prefixOperatorMethod = getOperatorMethod(OPERATOR_POSTFIX_INCREMENT);
3346 postfixOperatorMethod = getOperatorMethod(OPERATOR_PREFIX_INCREMENT);
3349 if (method->getOperator() == OPERATOR_POSTFIX_DECREMENT ||
3350 method->getOperator() == OPERATOR_PREFIX_DECREMENT) {
3351 prefixOperatorMethod = getOperatorMethod(OPERATOR_POSTFIX_DECREMENT);
3352 postfixOperatorMethod = getOperatorMethod(OPERATOR_PREFIX_DECREMENT);
3355 if (method->getOperator() == OPERATOR_POSTFIX_INCREMENT ||
3356 method->getOperator() == OPERATOR_PREFIX_INCREMENT ||
3357 method->getOperator() == OPERATOR_POSTFIX_DECREMENT ||
3358 method->getOperator() == OPERATOR_PREFIX_DECREMENT) {
3360 if (prefixOperatorMethod ==
nullptr) {
3361 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": No prefix operator method found");
3362 scriptValid =
false;
3363 return preprocessedStatement;
3366 if (postfixOperatorMethod ==
nullptr) {
3367 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": No postfix operator method found");
3368 scriptValid =
false;
3369 return preprocessedStatement;
3374 if (method->isVariadic() ==
false &&
3375 method->getArgumentTypes().size() == 2) {
3377 auto operatorString = getOperatorAsString(nextOperator.operator_);
3379 string leftArgumentBrackets;
3380 int leftArgumentLength = 0;
3381 auto leftArgument = findLeftArgument(preprocessedStatement, nextOperator.idx - 1, leftArgumentLength, leftArgumentBrackets);
3383 string rightArgumentBrackets;
3384 int rightArgumentLength = 0;
3385 auto rightArgument = findRightArgument(preprocessedStatement, nextOperator.idx + operatorString.size(), rightArgumentLength, rightArgumentBrackets);
3387 if (leftArgument.empty() ==
false) {
3389 auto leftArgumentNewLines = 0;
3390 for (
auto i = 0; i < leftArgument.size(); i++) {
3391 auto c = leftArgument[i];
3392 if (c ==
'\n') leftArgumentNewLines++;
else break;
3395 preprocessedStatement =
3398 prefixOperatorMethod->getMethodName() +
"(" +
_StringTools::substring(leftArgument, leftArgumentNewLines) +
", " + to_string(encodeOperatorString(operatorString)) +
")" +
3399 _StringTools::substring(preprocessedStatement, nextOperator.idx + operatorString.size(), preprocessedStatement.size()
3402 if (rightArgument.empty() ==
false) {
3404 preprocessedStatement =
3406 postfixOperatorMethod->getMethodName() +
"(" + rightArgument +
", " + to_string(encodeOperatorString(operatorString)) +
")" +
3407 _StringTools::substring(preprocessedStatement, nextOperator.idx + operatorString.size() + rightArgumentLength, preprocessedStatement.size());
3409 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": Requires left or right argument");
3410 scriptValid =
false;
3411 return preprocessedStatement;
3414 if (method->isVariadic() ==
true ||
3415 method->getArgumentTypes().size() == 3) {
3417 auto operatorString = getOperatorAsString(nextOperator.operator_);
3419 string leftArgumentBrackets;
3420 int leftArgumentLength = 0;
3421 auto leftArgument = findLeftArgument(preprocessedStatement, nextOperator.idx - 1, leftArgumentLength, leftArgumentBrackets);
3423 string rightArgumentBrackets;
3424 int rightArgumentLength = 0;
3425 auto rightArgument = findRightArgument(preprocessedStatement, nextOperator.idx + operatorString.size(), rightArgumentLength, rightArgumentBrackets);
3427 if (leftArgument.empty() ==
true || rightArgument.empty() ==
true) {
3428 _Console::printLine(getStatementInformation(statement, getStatementSubLineIdx(preprocessedStatement, nextOperator.idx)) +
": Requires left and right argument");
3429 scriptValid =
false;
3430 return preprocessedStatement;
3433 if (nextOperator.operator_ == OPERATOR_SET) {
3434 leftArgument =
"\"" +
_StringTools::replace(doStatementPreProcessing(leftArgument, statement),
"\"",
"\\\"") +
"\"";
3437 auto leftArgumentNewLines = 0;
3438 for (
auto i = 0; i < leftArgument.size(); i++) {
3439 auto c = leftArgument[i];
3440 if (c ==
'\n') leftArgumentNewLines++;
else break;
3443 preprocessedStatement =
3446 method->getMethodName() +
"(" +
_StringTools::substring(leftArgument, leftArgumentNewLines) +
", " + rightArgument +
", " + to_string(encodeOperatorString(operatorString)) +
")" +
3447 _StringTools::substring(preprocessedStatement, nextOperator.idx + operatorString.size() + rightArgumentLength, preprocessedStatement.size()
3452 nextOperator = StatementOperator();
3455 return preprocessedStatement;
3458 bool MinitScript::getObjectMemberAccess(
const string_view& executableStatement, string_view&
object, string_view& method,
int& methodStartIdx,
const Statement& statement) {
3460 auto objectMemberAccess =
false;
3461 auto objectStartIdx = string::npos;
3462 auto objectEndIdx = string::npos;
3463 auto memberCallStartIdx = string::npos;
3464 auto memberCallEndIdx = string::npos;
3468 auto bracketCount = 0;
3469 auto squareBracketCount = 0;
3470 auto curlyBracketCount = 0;
3471 for (
auto i = 0; i < executableStatement.size(); i++) {
3473 auto c = executableStatement[i];
3475 if ((c ==
'"' || c ==
'\'') && lc !=
'\\') {
3476 if (quote ==
'\0') {
3483 if (quote !=
'\0') {
3493 squareBracketCount++;
3496 squareBracketCount--;
3499 curlyBracketCount++;
3502 curlyBracketCount--;
3505 lc ==
'-' && c ==
'>' &&
3506 bracketCount == 0 &&
3507 squareBracketCount == 0 &&
3508 curlyBracketCount == 0) {
3510 auto objectStartIdxCandidate = 0;
3511 auto objectEndIdxCandidate = i - 1;
3512 auto memberCallStartIdxCandidate = i + 1;
3513 auto memberCallEndIdxCandidate = executableStatement.size();
3515 auto objectCandidate =
_StringTools::viewTrim(string_view(&executableStatement[objectStartIdxCandidate], objectEndIdxCandidate - objectStartIdxCandidate));
3516 auto methodCandidate =
_StringTools::viewTrim(string_view(&executableStatement[memberCallStartIdxCandidate], memberCallEndIdxCandidate - memberCallStartIdxCandidate));
3518 if (objectCandidate.empty() ==
false &&
3519 methodCandidate.empty() ==
false &&
3520 (viewIsStringLiteral(objectCandidate) ==
true || viewIsVariableAccess(objectCandidate) ==
true || viewIsCall(objectCandidate) ==
true)) {
3522 objectStartIdx = objectStartIdxCandidate;
3523 objectEndIdx = objectEndIdxCandidate;
3524 memberCallStartIdx = memberCallStartIdxCandidate;
3525 memberCallEndIdx = memberCallEndIdxCandidate;
3527 object = objectCandidate;
3528 method = methodCandidate;
3530 methodStartIdx = memberCallStartIdx;
3531 objectMemberAccess =
true;
3536 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
3539 return objectMemberAccess;
3542 void MinitScript::dumpScriptState(
ScriptState& scriptState,
const string& message) {
3543 _Console::printLine(
"MinitScript::dumpScriptState(): " + (message.empty() ==
false?message +
": ":
"") + to_string(scriptStateStack.size()) +
" on stack");
3552 array<string, 9> blockStackTypes {
3563 for (
const auto& block: scriptState.
blockStack) {
3569 bool MinitScript::call(
int scriptIdx, span<Variable>& arguments,
Variable& returnValue,
bool pushScriptState) {
3571 if (scriptIdx < 0 || scriptIdx >= scripts.size()) {
3572 _Console::printLine(
"MinitScript::call(): Invalid script index: " + to_string(scriptIdx));
3575 auto& script = scripts[scriptIdx];
3577 if (script.type != Script::TYPE_FUNCTION &&
3578 script.type != Script::TYPE_STACKLET) {
3579 _Console::printLine(
"MinitScript::call(): " + (script.name.empty() ==
false?script.name:script.condition) +
": Script is not a function/callable/stacklet.");
3583 ScriptState currentScriptState = getScriptState();
3585 if (pushScriptState ==
true) {
3586 if (script.type == Script::TYPE_STACKLET) {
3587 _Console::printLine(
"MinitScript::call(): " + script.condition +
": Stacklets can not be called with a stack.");
3590 this->pushScriptState();
3592 auto& scriptState = getScriptState();
3594 auto argumentIdx = 0;
3595 for (
const auto& argument: script.arguments) {
3596 if (argumentIdx == arguments.size()) {
3600 if (argument.privateScope ==
true) {
3601 arguments[argumentIdx].setPrivateScope();
3603 arguments[argumentIdx].unsetPrivateScope();
3606 setVariable(argument.name, arguments[argumentIdx],
nullptr, argument.reference);
3610 resetScriptExecutationState(scriptIdx, STATEMACHINESTATE_NEXT_STATEMENT);
3613 if (script.type != Script::TYPE_STACKLET) {
3614 _Console::printLine(
"MinitScript::call(): " + script.condition +
": Function/Callable can not be called with no stack.");
3618 resetStackletScriptExecutationState(scriptIdx, STATEMACHINESTATE_NEXT_STATEMENT);
3622 auto& scriptState = getScriptState();
3624 scriptState.running =
true;
3630 if (getScriptState().running ==
false)
break;
3634 const auto& scriptState = getScriptState();
3636 returnValue.
setValue(scriptState.returnValue);
3639 if (pushScriptState ==
true) {
3642 auto& scriptState = getScriptState();
3643 scriptState.state = currentScriptState.
state;
3644 scriptState.lastState = currentScriptState.
lastState;
3646 scriptState.running = currentScriptState.
running;
3647 scriptState.scriptIdx = currentScriptState.
scriptIdx;
3648 scriptState.statementIdx = currentScriptState.
statementIdx;
3650 scriptState.returnValue = currentScriptState.
returnValue;
3653 tryGarbageCollection();
3655 if (isFunctionRunning() ==
false && deferredEmit.empty() ==
false) {
3656 auto condition = deferredEmit;
3657 deferredEmit.clear();
3664 const vector<MinitScript::Method*> MinitScript::getMethods() {
3665 vector<Method*> methods;
3666 for (
const auto& [methodName, method]: this->methods) {
3667 if (method->isPrivate() ==
true)
continue;
3668 methods.push_back(method);
3677 array<string, 6> prefixes {
3685 array<string, 6> sortPrefixes {
3694 for (
const auto& prefix: prefixes) {
3702 for (
const auto& prefix: prefixes) {
3709 if (aName == bName) {
3710 return aPrefix + (aPrefixIdx < 6?sortPrefixes[aPrefixIdx]:
"") + aName < bPrefix + (bPrefixIdx < 6?sortPrefixes[bPrefixIdx]:
"") + bName;
3712 return aPrefix + aName < bPrefix + bName;
3717 sort(methods.begin(), methods.end(), sortFunction);
3722 const vector<MinitScript::Method*> MinitScript::getOperatorMethods() {
3723 vector<Method*> methods;
3724 for (
const auto& [operatorId, method]: operators) {
3725 methods.push_back(method);
3730 const string MinitScript::getScriptInformation(
int scriptIdx,
bool includeStatements) {
3731 if (scriptIdx < 0 || scriptIdx >= scripts.size()) {
3732 _Console::printLine(
"MinitScript::getScriptInformation(): invalid script index: " + to_string(scriptIdx));
3735 const auto& script = scripts[scriptIdx];
3737 string argumentsString;
3738 switch(script.type) {
3739 case Script::TYPE_FUNCTION:
3740 case Script::TYPE_STACKLET: {
3741 for (
const auto& argument: script.arguments) {
3742 if (argumentsString.empty() ==
false) argumentsString+=
", ";
3743 if (argument.reference ==
true) argumentsString+=
"&";
3744 if (argument.privateScope ==
true) argumentsString+=
"&";
3745 argumentsString+= argument.name;
3747 argumentsString =
"(" + argumentsString +
")";
3748 if (script.type == Script::TYPE_FUNCTION) result+=
"function: ";
else result+=
"stacklet: ";
3751 case Script::TYPE_ON: result+=
"on: ";
break;
3752 case Script::TYPE_ONENABLED: result+=
"on-enabled: ";
break;
3755 if (script.condition.empty() ==
false)
3756 result+= script.condition + argumentsString +
"; ";
3757 if (script.name.empty() ==
false) {
3758 result+=
"name = '" + script.name + argumentsString +
"';\n";
3762 if (includeStatements ==
true) {
3764 auto formatStatement = [&](
const string& statement) {
3767 if (statementMethodEndIdx == string::npos) statementMethodEndIdx = statement.size();
3769 if (statementMethod ==
"elseif") indent-= 1;
else
3770 if (statementMethod ==
"else") indent-= 1;
else
3771 if (statementMethod ==
"case") indent-= 1;
else
3772 if (statementMethod ==
"default") indent-= 1;
else
3773 if (statementMethod ==
"end") indent-= 1;
3774 for (
auto i = 0; i < indent; i++) result+=
" ";
3776 if (statementMethod ==
"if") indent+= 1;
else
3777 if (statementMethod ==
"elseif") indent+= 1;
else
3778 if (statementMethod ==
"else") indent+= 1;
else
3779 if (statementMethod ==
"forTime") indent+= 1;
else
3780 if (statementMethod ==
"forCondition") indent+= 1;
else
3781 if (statementMethod ==
"switch") indent+= 1;
else
3782 if (statementMethod ==
"case") indent+= 1;
else
3783 if (statementMethod ==
"default") indent+= 1;
3788 "\t" +
" " +
": start" +
"\n";
3789 for (
const auto& statement: script.statements) {
3790 string newLineIndent;
for (
auto i = 0; i < indent + 2; i++) newLineIndent+=
" ";
3799 _StringTools::replace(formatStatement(statement.executableStatement),
"\n",
"\n\t :" + newLineIndent)
3812 const string MinitScript::getInformation() {
3814 result+=
"Script: " + scriptPathName +
"/" + scriptFileName +
" (runs " + (native ==
true?
"natively":
"interpreted") +
")" +
"\n\n";
3818 result+=
"State Machine States:\n";
3820 vector<string> states;
3821 for (
const auto& [stateMachineStateId, stateMachineState]: stateMachineStates) {
3823 state = stateMachineState->getName() +
"(" + to_string(stateMachineState->getId()) +
")";
3824 states.push_back(state);
3826 sort(states.begin(), states.end());
3827 for (
const auto& state: states) result+= state+
"\n";
3832 result+=
"Methods:\n";
3834 vector<string> methods;
3835 for (
const auto& [methodName, method]: this->methods) {
3836 if (method->isPrivate() ==
true)
continue;
3837 string methodDescription;
3838 methodDescription+= method->getMethodName();
3839 methodDescription+=
"(";
3840 methodDescription+= method->getArgumentsInformation();
3841 methodDescription+=
"): ";
3842 methodDescription+= Variable::getReturnTypeAsString(method->getReturnValueType(), method->isReturnValueNullable());
3843 methods.push_back(methodDescription);
3845 sort(methods.begin(), methods.end());
3846 for (
const auto& method: methods) result+= method +
"\n";
3851 result+=
"Operators:\n";
3853 vector<string> operators;
3854 for (
const auto& [operatorId, method]: this->operators) {
3855 string operatorString;
3856 operatorString+= getOperatorAsString(method->getOperator());
3857 operatorString+=
" --> ";
3858 operatorString+= method->getMethodName();
3859 operatorString+=
"(";
3860 operatorString+= method->getArgumentsInformation();
3861 operatorString+=
"): ";
3862 operatorString+= Variable::getReturnTypeAsString(method->getReturnValueType(), method->isReturnValueNullable());
3863 operators.push_back(operatorString);
3865 sort(operators.begin(), operators.end());
3866 for (
const auto& method: operators) result+= method +
"\n";
3871 result+=
"Variables:\n";
3873 const auto& scriptState = getScriptState();
3874 vector<string> variables;
3875 for (
const auto& [scriptVariableName, scriptVariableValue]: scriptState.variables) {
3877 variable+= scriptVariableName +
" = " + scriptVariableValue->getAsString();
3878 variables.push_back(variable);
3880 sort(variables.begin(), variables.end());
3881 for (
const auto& variable: variables) result+= variable +
"\n";
3886 result+=
"Script:\n";
3889 for (
const auto& script: scripts) {
3890 result+= getScriptInformation(scriptIdx);
3899 void MinitScript::registerStateMachineStates() {
3901 if (native ==
false) {
3908 virtual const string getName()
override {
3909 return "STATEMACHINESTATE_NEXT_STATEMENT";
3911 virtual int getId()
override {
3912 return STATEMACHINESTATE_NEXT_STATEMENT;
3914 virtual void execute()
override {
3924 registerStateMachineState(
new ScriptStateNextStatement(
this));
3933 virtual const string getName()
override {
3934 return "STATEMACHINESTATE_WAIT";
3936 virtual int getId()
override {
3937 return STATEMACHINESTATE_WAIT;
3939 virtual void execute()
override {
3944 #if !defined(MINITSCRIPT_NO_SLEEP)
3950 registerStateMachineState(
new ScriptStateWait(
this));
3959 virtual const string getName()
override {
3960 return "STATEMACHINESTATE_WAIT_FOR_CONDITION";
3962 virtual int getId()
override {
3963 return STATEMACHINESTATE_WAIT_FOR_CONDITION;
3965 virtual void execute()
override {
3971 if (scriptIdxToStart == SCRIPTIDX_NONE) {
3979 registerStateMachineState(
new ScriptStateWaitForCondition(
this));
3983 void MinitScript::registerMethods() {
3985 for (
const auto& [scriptMethodId, scriptMethod]: methods)
delete scriptMethod;
3989 minitScriptMath = make_unique<MathMethods>(
this);
3990 minitScriptMath->registerMethods();
3994 BaseMethods::registerMethods(
this);
3997 StringMethods::registerMethods(
this);
4000 ByteArrayMethods::registerMethods(
this);
4003 ArrayMethods::registerMethods(
this);
4006 MapMethods::registerMethods(
this);
4009 SetMethods::registerMethods(
this);
4012 ScriptMethods::registerMethods(
this);
4016 ApplicationMethods::registerMethods(
this);
4019 ConsoleMethods::registerMethods(
this);
4022 ContextMethods::registerMethods(
this);
4025 CryptographyMethods::registerMethods(
this);
4028 FileSystemMethods::registerMethods(
this);
4031 JSONMethods::registerMethods(
this);
4034 NetworkMethods::registerMethods(
this);
4037 TimeMethods::registerMethods(
this);
4040 XMLMethods::registerMethods(
this);
4043 for (
const auto dataType: dataTypes) {
4044 if (dataType->isMathDataType() ==
true) minitScriptMath->registerDataType(dataType);
4045 dataType->registerMethods(
this);
4049 for (
const auto& [scriptMethodName, scriptMethod]: methods) {
4050 auto methodOperator = scriptMethod->getOperator();
4051 if (methodOperator != OPERATOR_NONE) {
4052 auto methodOperatorString = getOperatorAsString(methodOperator);
4053 auto scriptOperatorIt = operators.find(
static_cast<uint8_t
>(methodOperator));
4054 if (scriptOperatorIt != operators.end()) {
4055 _Console::printLine(
"MinitScript::registerMethods(): Operator '" + methodOperatorString +
"' already registered for method " + scriptMethod->getMethodName() +
"");
4058 operators[
static_cast<uint8_t
>(methodOperator)] = scriptMethod;
4063 void MinitScript::registerVariables() {
4065 for (
const auto& [variableName, variable]: getRootScriptState().variables)
delete variable;
4066 getRootScriptState().variables.clear();
4069 minitScriptMath->registerConstants();
4073 BaseMethods::registerConstants(
this);
4076 StringMethods::registerConstants(
this);
4079 ByteArrayMethods::registerConstants(
this);
4082 ArrayMethods::registerConstants(
this);
4085 MapMethods::registerConstants(
this);
4088 SetMethods::registerConstants(
this);
4091 ScriptMethods::registerConstants(
this);
4095 ApplicationMethods::registerConstants(
this);
4098 ConsoleMethods::registerConstants(
this);
4101 ContextMethods::registerConstants(
this);
4104 CryptographyMethods::registerConstants(
this);
4107 FileSystemMethods::registerConstants(
this);
4110 JSONMethods::registerConstants(
this);
4113 NetworkMethods::registerConstants(
this);
4116 TimeMethods::registerConstants(
this);
4119 XMLMethods::registerConstants(
this);
4122 for (
const auto dataType: dataTypes) dataType->registerConstants(
this);
4125 void MinitScript::createLamdaFunction(
Variable& variable,
const vector<string_view>& arguments,
const string_view& functionScriptCode,
int lineIdx,
bool populateThis,
const Statement& statement,
const string& nameHint) {
4127 auto functionName = string() +
"lamda_function_" + (nameHint.empty() ==
true?
"":
_StringTools::toLowerCase(nameHint) +
"_") + to_string(inlineFunctionIdx++);
4128 auto inlineFunctionScriptCode =
"function: " + functionName +
"(";
4129 if (populateThis ==
true) inlineFunctionScriptCode+=
"&&$this";
4130 auto argumentIdx = 0;
4131 for (
const auto& argument: arguments) {
4132 if (argumentIdx > 0 || populateThis ==
true) inlineFunctionScriptCode+=
",";
4133 inlineFunctionScriptCode+= argument;
4136 inlineFunctionScriptCode+= string() +
")" +
"\n";
4138 inlineFunctionScriptCode+= string(functionScriptCode);
4139 inlineFunctionScriptCode+=
"\n";
4140 inlineFunctionScriptCode+= string() +
"end" +
"\n";
4144 deferredInlineScriptCodes.push_back(make_pair(lineIdx - 2, inlineFunctionScriptCode));
4149 void MinitScript::createStacklet(
Variable& variable,
const string& scopeName,
const vector<string_view>& arguments,
const string_view& stackletScriptCode,
int lineIdx,
const Statement& statement) {
4151 auto stackletName = string() +
"stacklet_" + to_string(inlineStackletIdx++);
4152 auto inlineStackletScriptCode =
"stacklet: " + stackletName +
"(" + scopeName +
")" +
"\n";
4154 inlineStackletScriptCode+= string(stackletScriptCode);
4155 inlineStackletScriptCode+=
"\n";
4156 inlineStackletScriptCode+= string() +
"end" +
"\n";
4160 deferredInlineScriptCodes.push_back(make_pair(lineIdx - 2, inlineStackletScriptCode));
4169 auto lineIdx = statement.
line;
4170 auto bracketCount = 0;
4171 auto squareBracketCount = 0;
4172 auto curlyBracketCount = 0;
4174 auto arrayValueStart = string::npos;
4175 auto arrayValueEnd = string::npos;
4176 auto inlineFunctionSignatureStartCandidate = string::npos;
4177 auto inlineFunctionLineIdxCandidate = LINE_NONE;
4178 auto inlineFunctionLineIdx = LINE_NONE;
4183 auto pushToArray = [&]() ->
void {
4185 if (arrayValueStart != string::npos) {
4186 arrayValueEnd = i - 1;
4187 auto arrayValueLength = arrayValueEnd - arrayValueStart + 1;
4188 if (arrayValueLength > 0) {
4189 auto arrayValueStringView =
_StringTools::viewTrim(string_view(&initializerString[arrayValueStart], arrayValueLength));
4190 if (arrayValueStringView.empty() ==
false) {
4198 arrayValueStart = string::npos;
4199 arrayValueEnd = string::npos;
4201 inlineFunctionSignatureStartCandidate = string::npos;
4202 inlineFunctionLineIdxCandidate = LINE_NONE;
4203 inlineFunctionLineIdx = LINE_NONE;
4206 for (; i < initializerString.size(); i++) {
4207 auto c = initializerString[i];
4212 auto comment =
false;
4213 for (
auto j = i + 1; j < initializerString.size(); j++) {
4214 auto _c = initializerString[j];
4223 for (j++; j < initializerString.size(); j++) {
4224 if (initializerString[j] ==
'\n')
break;
4235 if (comment ==
true)
continue;
4238 if (squareBracketCount == 1 && curlyBracketCount == 0 && (c ==
'"' || c ==
'\'') && lc !=
'\\') {
4239 if (quote ==
'\0') {
4241 if (arrayValueStart == string::npos) arrayValueStart = i;
4245 if (arrayValueEnd == string::npos) arrayValueEnd = i;
4249 if (quote ==
'\0') {
4251 if (squareBracketCount == 1 && curlyBracketCount == 0 && bracketCount == 0 && c ==
',') {
4259 if (bracketCount == 1) {
4260 inlineFunctionSignatureStartCandidate = i;
4261 inlineFunctionLineIdxCandidate = lineIdx;
4267 if (inlineFunctionSignatureStartCandidate != string::npos && bracketCount == 0 && arrayValueStart == string::npos) {
4268 arrayValueStart = inlineFunctionSignatureStartCandidate;
4269 inlineFunctionLineIdx = inlineFunctionLineIdxCandidate;
4272 inlineFunctionSignatureStartCandidate = string::npos;
4273 inlineFunctionLineIdxCandidate = LINE_NONE;
4276 if (c ==
'[' && curlyBracketCount == 0 && bracketCount == 0) {
4278 if (squareBracketCount == 1) arrayValueStart = i;
4280 squareBracketCount++;
4283 if (c ==
']' && curlyBracketCount == 0 && bracketCount == 0) {
4284 squareBracketCount--;
4286 if (squareBracketCount == 0) {
4291 if (squareBracketCount == 1) {
4293 inlineFunctionSignatureStartCandidate = string::npos;
4294 inlineFunctionLineIdxCandidate = LINE_NONE;
4296 if (arrayValueStart != string::npos) {
4298 auto arrayValueLength = arrayValueEnd - arrayValueStart + 1;
4299 if (arrayValueLength > 0) {
4300 auto arrayValueStringView =
_StringTools::viewTrim(string_view(&initializerString[arrayValueStart], arrayValueLength));
4301 if (arrayValueStringView.empty() ==
false) {
4302 auto arrayValue = initializeArray(arrayValueStringView, minitScript, scriptIdx, statement);
4307 arrayValueStart = string::npos;
4308 arrayValueEnd = string::npos;
4311 inlineFunctionLineIdx = LINE_NONE;
4315 if (c ==
'{' && squareBracketCount == 1 && bracketCount == 0) {
4317 if (curlyBracketCount == 0) {
4318 if (arrayValueStart == string::npos) arrayValueStart = i;
4321 curlyBracketCount++;
4324 if (c ==
'}' && squareBracketCount == 1 && bracketCount == 0) {
4325 curlyBracketCount--;
4327 if (curlyBracketCount == 0) {
4329 inlineFunctionSignatureStartCandidate = string::npos;
4330 inlineFunctionLineIdxCandidate = LINE_NONE;
4332 if (arrayValueStart != string::npos) {
4334 auto arrayValueLength = arrayValueEnd - arrayValueStart + 1;
4335 if (arrayValueLength > 0) {
4336 auto arrayValueStringView =
_StringTools::viewTrim(string_view(&initializerString[arrayValueStart], arrayValueLength));
4337 if (arrayValueStringView.empty() ==
false) {
4338 vector<string_view> lamdaFunctionArguments;
4339 string_view lamdaFunctionScriptCode;
4340 int lamdaFunctionLineIdx = inlineFunctionLineIdx;
4341 if (viewIsLamdaFunction(arrayValueStringView, lamdaFunctionArguments, lamdaFunctionScriptCode, lamdaFunctionLineIdx) ==
true) {
4343 minitScript->
createLamdaFunction(arrayValue, lamdaFunctionArguments, lamdaFunctionScriptCode, lamdaFunctionLineIdx,
false, statement);
4346 auto arrayValue = initializeMapSet(arrayValueStringView, minitScript, scriptIdx, statement);
4352 arrayValueStart = string::npos;
4353 arrayValueEnd = string::npos;
4356 inlineFunctionLineIdx = LINE_NONE;
4360 if (squareBracketCount == 1 && curlyBracketCount == 0 && bracketCount == 0 && arrayValueStart == string::npos && c !=
' ' && c !=
'\t' && c !=
'\n') {
4361 arrayValueStart = i;
4365 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
4368 auto initalizer = make_unique<MinitScript::Variable::Initializer>(
string(initializerString), statement,
nullptr);
4379 auto subLineIdx = 0;
4380 auto bracketCount = 0;
4381 auto curlyBracketCount = 0;
4382 auto squareBracketCount = 0;
4384 auto mapKeyStart = string::npos;
4385 auto mapKeyEnd = string::npos;
4386 auto mapValueStart = string::npos;
4387 auto mapValueEnd = string::npos;
4388 enum ParseMode { PARSEMODE_KEY, PARSEMODE_VALUE };
4389 auto parseMode = PARSEMODE_KEY;
4390 auto inlineFunctionSignatureStartCandidate = string::npos;
4391 auto inlineFunctionLineIdxCandidate = LINE_NONE;
4392 auto inlineFunctionLineIdx = LINE_NONE;
4393 auto mapKeyLineIdx = LINE_NONE;
4394 auto hasValues =
false;
4399 auto insertMapKeyValuePair = [&]() ->
void {
4402 auto dequotedMapKey =
false;
4404 if (mapKeyStart != string::npos && mapKeyEnd != string::npos) {
4406 auto mapKeyLength = mapKeyEnd - mapKeyStart + 1;
4407 if (mapKeyLength > 0) {
4409 if (viewIsStringLiteral(mapKey) ==
true) {
4410 mapKey = dequote(mapKey);
4411 dequotedMapKey =
true;
4413 if (mapKey.empty() ==
true) mapKey = string_view();
4417 mapKeyStart = string::npos;
4418 mapKeyEnd = string::npos;
4420 if (mapKey.empty() ==
true) {
4423 if (viewIsKey(mapKey) ==
false) {
4426 auto _private = dequotedMapKey ==
true?
false:viewIsKeyPrivate(mapKey);
4427 if (_private ==
true) mapKey = viewGetPrivateKey(mapKey);
4429 if (mapValueStart != string::npos && mapValueEnd != string::npos) {
4430 auto mapValueLength = mapValueEnd - mapValueStart + 1;
4432 if (mapValueLength > 0) {
4433 auto mapValueStringView =
_StringTools::viewTrim(string_view(&initializerString[mapValueStart], mapValueLength));
4434 if (mapValueStringView.empty() ==
false) {
4439 variable.
setMapEntry(
string(mapKey), mapValue, _private);
4450 mapKeyLineIdx = LINE_NONE;
4452 mapValueStart = string::npos;
4453 mapValueEnd = string::npos;
4455 inlineFunctionSignatureStartCandidate = string::npos;
4456 inlineFunctionLineIdxCandidate = LINE_NONE;
4457 inlineFunctionLineIdx = LINE_NONE;
4459 parseMode = PARSEMODE_KEY;
4463 for (; i < initializerString.size(); i++) {
4465 auto c = initializerString[i];
4466 auto nc = i < initializerString.size() - 1?initializerString[i + 1]:
'\0';
4472 auto comment =
false;
4473 for (
auto j = i + 1; j < initializerString.size(); j++) {
4474 auto _c = initializerString[j];
4483 for (j++; j < initializerString.size(); j++) {
4484 if (initializerString[j] ==
'\n')
break;
4495 if (comment ==
true)
continue;
4498 if (curlyBracketCount == 1 && squareBracketCount == 0 && (c ==
'"' || c ==
'\'') && lc !=
'\\') {
4500 if (quote ==
'\0') {
4503 if (parseMode == PARSEMODE_KEY) {
4504 if (mapKeyStart == string::npos) {
4506 mapKeyLineIdx = subLineIdx;
4510 if (parseMode == PARSEMODE_VALUE) {
4511 if (mapValueStart == string::npos) mapValueStart = i;
4520 if (quote ==
'\0') {
4522 if (curlyBracketCount == 1 && squareBracketCount == 0 && bracketCount == 0 && c ==
':' && nc !=
':' && lc !=
':' && lc !=
'\\') {
4524 if (mapKeyStart != string::npos) {
4528 parseMode = PARSEMODE_VALUE;
4532 if (curlyBracketCount == 1 && squareBracketCount == 0 && bracketCount == 0 && c ==
',') {
4534 if (mapValueStart != string::npos) {
4535 mapValueEnd = i - 1;
4537 if (mapKeyStart != string::npos && mapValueStart == string::npos) {
4541 insertMapKeyValuePair();
4549 if (bracketCount == 1) {
4550 inlineFunctionSignatureStartCandidate = i;
4551 inlineFunctionLineIdxCandidate = statement.
line + subLineIdx;
4557 if (inlineFunctionSignatureStartCandidate != string::npos && bracketCount == 0 && mapValueStart == string::npos) {
4558 mapValueStart = inlineFunctionSignatureStartCandidate;
4559 inlineFunctionLineIdx = inlineFunctionLineIdxCandidate;
4562 inlineFunctionSignatureStartCandidate = string::npos;
4563 inlineFunctionLineIdxCandidate = LINE_NONE;
4566 if (c ==
'{' && squareBracketCount == 0 && bracketCount == 0) {
4569 curlyBracketCount++;
4571 if (curlyBracketCount == 2) {
4572 if (mapValueStart == string::npos) mapValueStart = i;
4576 if (c ==
'}' && squareBracketCount == 0 && bracketCount == 0) {
4578 curlyBracketCount--;
4580 if (curlyBracketCount == 0) {
4583 if (mapValueStart != string::npos) {
4584 mapValueEnd = i - 1;
4587 if (mapKeyStart != string::npos) {
4591 insertMapKeyValuePair();
4594 if (curlyBracketCount == 1) {
4597 auto dequotedMapKey =
false;
4599 if (mapKeyStart != string::npos) {
4600 if (mapKeyEnd == string::npos) mapKeyEnd = i;
4601 auto mapKeyLength = mapKeyEnd - mapKeyStart + 1;
4602 if (mapKeyLength > 0) mapKey =
_StringTools::viewTrim(string_view(&initializerString[mapKeyStart], mapKeyLength));
4603 if (viewIsStringLiteral(mapKey) ==
true) {
4604 mapKey = dequote(mapKey);
4605 dequotedMapKey =
true;
4609 mapKeyStart = string::npos;
4610 mapKeyEnd = string::npos;
4612 if (mapKey.empty() ==
true || viewIsKey(mapKey) ==
false) {
4615 auto _private = dequotedMapKey ==
true?
false:viewIsKeyPrivate(mapKey);
4616 if (_private ==
true) mapKey = viewGetPrivateKey(mapKey);
4618 inlineFunctionSignatureStartCandidate = string::npos;
4619 inlineFunctionLineIdxCandidate = LINE_NONE;
4621 if (mapValueStart != string::npos) {
4623 auto mapValueLength = mapValueEnd - mapValueStart + 1;
4624 if (mapValueLength > 0) {
4625 auto mapValueStringView =
_StringTools::viewTrim(string_view(&initializerString[mapValueStart], mapValueLength));
4626 if (mapValueStringView.empty() ==
false) {
4627 vector<string_view> lamdaFunctionArguments;
4628 string_view lamdaFunctionScriptCode;
4629 int lamdaFunctionLineIdx = inlineFunctionLineIdx;
4630 if (viewIsLamdaFunction(mapValueStringView, lamdaFunctionArguments, lamdaFunctionScriptCode, lamdaFunctionLineIdx) ==
true) {
4632 minitScript->
createLamdaFunction(mapValue, lamdaFunctionArguments, lamdaFunctionScriptCode, lamdaFunctionLineIdx,
true, statement,
string(mapKey));
4633 variable.
setMapEntry(
string(mapKey), mapValue, _private);
4638 auto mapValue = initializeMapSet(mapValueStringView, minitScript, scriptIdx, statement);
4639 variable.
setMapEntry(
string(mapKey), mapValue, _private);
4647 mapValueStart = string::npos;
4648 mapValueEnd = string::npos;
4651 inlineFunctionLineIdx = LINE_NONE;
4654 parseMode = PARSEMODE_KEY;
4655 mapKeyLineIdx = LINE_NONE;
4659 if (c ==
'[' && curlyBracketCount == 1 && bracketCount == 0) {
4661 if (squareBracketCount == 0) {
4662 if (mapValueStart == string::npos) mapValueStart = i;
4665 squareBracketCount++;
4668 if (c ==
']' && squareBracketCount == 1 && curlyBracketCount == 1 && bracketCount == 0) {
4669 squareBracketCount--;
4671 if (squareBracketCount == 0 && mapValueStart != string::npos && initializerString[mapValueStart] ==
'[') {
4674 auto dequotedMapKey =
false;
4676 if (mapKeyStart != string::npos) {
4677 auto mapKeyLength = mapKeyEnd - mapKeyStart + 1;
4678 if (mapKeyLength > 0) mapKey =
_StringTools::viewTrim(string_view(&initializerString[mapKeyStart], mapKeyLength));
4679 if (viewIsStringLiteral(mapKey) ==
true) {
4680 mapKey = dequote(mapKey);
4681 dequotedMapKey =
true;
4685 mapKeyStart = string::npos;
4686 mapKeyEnd = string::npos;
4688 if (mapKey.empty() ==
true || viewIsKey(mapKey) ==
false) {
4691 auto _private = dequotedMapKey ==
true?
false:viewIsKeyPrivate(mapKey);
4692 if (_private ==
true) mapKey = viewGetPrivateKey(mapKey);
4694 inlineFunctionSignatureStartCandidate = string::npos;
4695 inlineFunctionLineIdxCandidate = LINE_NONE;
4697 if (mapValueStart != string::npos) {
4699 auto mapValueLength = mapValueEnd - mapValueStart + 1;
4700 if (mapValueLength > 0) {
4701 auto mapValueStringView =
_StringTools::viewTrim(string_view(&initializerString[mapValueStart], mapValueLength));
4702 if (mapValueStringView.empty() ==
false) {
4703 auto mapValue = initializeArray(mapValueStringView, minitScript, scriptIdx, statement);
4704 variable.
setMapEntry(
string(mapKey), mapValue, _private);
4710 mapValueStart = string::npos;
4711 mapValueEnd = string::npos;
4714 inlineFunctionLineIdx = LINE_NONE;
4717 parseMode = PARSEMODE_KEY;
4718 mapKeyLineIdx = LINE_NONE;
4722 if (curlyBracketCount == 1 && squareBracketCount == 0 && bracketCount == 0 && c !=
' ' && c !=
'\t' && c !=
'\n') {
4723 if (parseMode == PARSEMODE_KEY && mapKeyStart == string::npos) {
4725 mapKeyLineIdx = subLineIdx;
4727 if (parseMode == PARSEMODE_VALUE && mapValueStart == string::npos) {
4733 lc = lc ==
'\\' && c ==
'\\'?
'\0':c;
4736 if (hasValues ==
false) {
4738 setVariable.
setType(TYPE_SET);
4740 for (
const auto& [mapVariableKey, mapVariableValue]: mapValueReference) {
4743 variable = setVariable;
4746 auto initalizer = make_unique<MinitScript::Variable::Initializer>(
string(initializerString), statement,
nullptr);
4752 void MinitScript::Variable::setFunctionCallStatement(
const string& initializerStatement,
MinitScript* minitScript,
int scriptIdx,
const Statement& statement) {
4753 setType(TYPE_FUNCTION_CALL);
4754 getStringValueReference().setValue(initializerStatement);
4759 initializerStatement,
4760 initializerStatement,
4761 MinitScript::STATEMENTIDX_NONE
4764 string_view methodName;
4765 vector<ParserArgument> arguments;
4766 string accessObjectMemberStatement;
4769 if (minitScript->
parseStatement(initializerStatement, methodName, arguments, initializerScriptStatement, accessObjectMemberStatement) ==
false) {
4772 if (minitScript->
createStatementSyntaxTree(scriptIdx, methodName, arguments, initializerScriptStatement, *evaluateSyntaxTree) ==
false) {
4775 getInitializerReference() =
new Initializer(initializerStatement, statement, evaluateSyntaxTree);
4783 arrayIdx = ARRAYIDX_NONE;
4785 auto accessOperatorLeftIdx = string::npos;
4786 auto accessOperatorRightIdx = string::npos;
4787 if (getVariableAccessOperatorLeftRightIndices(variableStatement, callerMethod, accessOperatorLeftIdx, accessOperatorRightIdx, subStatement) ==
false) {
4791 auto haveAccessOperator = accessOperatorLeftIdx != string::npos && accessOperatorRightIdx != string::npos;
4792 if (haveAccessOperator ==
true &&
4793 evaluateAccess(variableStatement, callerMethod, accessOperatorLeftIdx, accessOperatorRightIdx, arrayIdx, key, subStatement) ==
false) {
4798 if (haveAccessOperator ==
false) {
4803 while (haveAccessOperator ==
true) {
4807 if (key.empty() ==
false) {
4808 if (variablePtr->
getType() == TYPE_MAP) {
4812 auto mapIt = mapValueReference.find(key);
4813 if (mapIt != mapValueReference.end()) {
4815 parentVariable = variablePtr;
4817 variablePtr = mapIt->second;
4819 if (variablePtr->
isPrivate() ==
true && privateParentScope ==
false) {
4821 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Private variable: " + variableStatement +
": access not allowed from outside of object");
4823 parentVariable =
nullptr;
4827 if (expectVariable ==
true) {
4828 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": key not found: '" + key +
"'");
4831 parentVariable = variablePtr;
4836 if (variablePtr->
getType() == TYPE_SET) {
4840 auto setIt = setValueReference.find(key);
4841 if (setIt != setValueReference.end()) {
4843 setAccessBool = SETACCESSBOOL_TRUE;
4845 parentVariable = variablePtr;
4848 setAccessBool = SETACCESSBOOL_FALSE;
4850 parentVariable = variablePtr;
4855 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": map/set access operator, but variable is not of type map/set");
4859 if (variablePtr->
getType() == TYPE_ARRAY) {
4861 if (arrayIdx == ARRAYIDX_ADD) {
4863 parentVariable = variablePtr;
4867 if (arrayIdx >= ARRAYIDX_FIRST && arrayIdx < variablePtr->getArrayValueReference().size()) {
4869 parentVariable = variablePtr;
4873 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": index out of bounds: 0 <= " + to_string(arrayIdx) +
" < " + to_string(variablePtr->
getArrayValueReference().size()));
4877 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": access operator, expected array, but got: " + variablePtr->
getValueAsString());
4882 auto accessOperatorStartIdx = accessOperatorRightIdx;
4883 accessOperatorLeftIdx = string::npos;
4884 accessOperatorRightIdx = string::npos;
4885 if (getVariableAccessOperatorLeftRightIndices(variableStatement, callerMethod, accessOperatorLeftIdx, accessOperatorRightIdx, subStatement, accessOperatorStartIdx) ==
false) {
4891 haveAccessOperator = accessOperatorLeftIdx != string::npos && accessOperatorRightIdx != string::npos;
4892 if (haveAccessOperator ==
false) {
4896 if (evaluateAccess(variableStatement, callerMethod, accessOperatorLeftIdx, accessOperatorRightIdx, arrayIdx, key, subStatement) ==
false) {
4902 if (parentVariable !=
nullptr && parentVariable->
isPrivateScope() ==
true) privateParentScope =
true;
4909 inline void MinitScript::setVariableInternal(
const string& variableStatement,
Variable* parentVariable,
Variable* variablePtr, int64_t arrayIdx,
const string& key,
const Variable& variable,
const SubStatement* subStatement,
bool createReference) {
4911 if (variablePtr !=
nullptr) {
4913 if (createReference ==
true) {
4919 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Constant: " + variableStatement +
": assignment of constant is not allowed");
4924 if (key.empty() ==
false) {
4925 if (parentVariable ==
nullptr) {
4929 if (parentVariable->
getType() == MinitScript::TYPE_MAP) {
4932 parentVariable->
setMapEntry(key, createReference ==
false?Variable::createNonReferenceVariable(&variable):Variable::createReferenceVariable(&variable));
4934 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Constant: " + variableStatement +
": assignment of constant is not allowed");
4937 if (parentVariable->
getType() == MinitScript::TYPE_SET) {
4942 if (booleanValue ==
true) {
4948 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": set access operator: expected boolean variable to remove/insert key in set, but got " + variable.
getTypeAsString());
4951 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Constant: " + variableStatement +
": assignment of constant is not allowed");
4954 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": map/set access operator: expected map/set, but got " + parentVariable->
getTypeAsString() +
": '" + key +
"'");
4959 if (arrayIdx == ARRAYIDX_ADD) {
4960 if (parentVariable ==
nullptr) {
4961 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": [] array push operator without array");
4963 if (parentVariable->
getType() == MinitScript::TYPE_ARRAY) {
4967 parentVariable->
pushArrayEntry(createReference ==
false?Variable::createNonReferenceVariable(&variable):Variable::createReferenceVariable(&variable));
4969 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Constant: " + variableStatement +
": assignment of constant is not allowed");
4972 _Console::printLine((subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": [] array push operator: expected array, but got " + parentVariable->
getTypeAsString());
4979 inline bool MinitScript::evaluateInternal(
const string& statement,
const string& executableStatement,
Variable& returnValue,
bool pushScriptState) {
4983 "internal.script.evaluate(" + statement +
")",
4984 "internal.script.evaluate(" + executableStatement +
")",
4987 auto scriptEvaluateStatement =
"internal.script.evaluate(" + executableStatement +
")";
4989 string_view methodName;
4990 vector<ParserArgument> arguments;
4991 string accessObjectMemberStatement;
4993 if (parseStatement(scriptEvaluateStatement, methodName, arguments, evaluateStatement, accessObjectMemberStatement) ==
false) {
4996 if (createStatementSyntaxTree(SCRIPTIDX_NONE, methodName, arguments, evaluateStatement, evaluateSyntaxTree) ==
false) {
5000 if (pushScriptState ==
true) {
5001 this->pushScriptState();
5002 resetScriptExecutationState(SCRIPTIDX_NONE, STATEMACHINESTATE_NEXT_STATEMENT);
5004 getScriptState().running =
true;
5013 if (pushScriptState ==
true) popScriptState();
5025 arrayVariable.
setType(TYPE_ARRAY);
5027 if (arrayPointer ==
nullptr)
break;
5028 for (
const auto arrayEntry: *arrayPointer) {
5032 return arrayVariable;
5039 if (mapPointer ==
nullptr)
break;
5040 for (
const auto& [mapKey, mapValue]: *mapPointer) {
5041 mapVariable.
setMapEntry(mapKey, initializeVariable(*mapValue));
5046 case TYPE_FUNCTION_CALL:
5048 return executeStatement(
5059 inline bool MinitScript::viewIsKey(
const string_view& candidate) {
5060 if (candidate.empty() ==
true)
return false;
5062 if (candidate[i] ==
'-') i++;
5063 for (; i < candidate.size(); i++) {
5064 auto c = candidate[i];
5070 inline bool MinitScript::viewIsKeyPrivate(
const string_view& candidate) {
5071 if (candidate.empty() ==
true)
return false;
5072 if (candidate[0] ==
'-')
return true;
5076 inline const string_view MinitScript::viewGetPrivateKey(
const string_view& candidate) {
5077 return string_view(&candidate.data()[1], candidate.size() - 1);
5080 inline bool MinitScript::getVariableAccessOperatorLeftRightIndices(
const string& variableStatement,
const string& callerMethod, string::size_type& accessOperatorLeftIdx, string::size_type& accessOperatorRightIdx,
const SubStatement* subStatement,
int startIdx) {
5081 accessOperatorLeftIdx = string::npos;
5082 accessOperatorRightIdx = string::npos;
5083 auto haveKey =
false;
5084 auto squareBracketsCount = 0;
5087 haveKey = variableStatement[startIdx - 1] ==
'.';
5088 if (haveKey ==
true) accessOperatorLeftIdx = startIdx - 1;
5090 if (startIdx == 0) {
5093 for (
auto i = 0; i < variableStatement.length(); i++) {
5094 auto c = variableStatement[i];
5095 if (lc ==
':' && c ==
':') {
5103 for (
auto i = startIdx; i < variableStatement.length(); i++) {
5104 auto c = variableStatement[i];
5105 if (haveKey ==
true) {
5108 accessOperatorRightIdx = i;
5114 accessOperatorRightIdx = i;
5119 _Console::printLine(
"MinitScript::" + callerMethod +
"(): " + (subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": unexpected char: ']'");
5123 if (c ==
'.' && squareBracketsCount == 0) {
5125 accessOperatorLeftIdx = i;
5128 if (squareBracketsCount == 0) accessOperatorLeftIdx = i;
5129 squareBracketsCount++;
5132 squareBracketsCount--;
5133 if (squareBracketsCount == 0) {
5135 accessOperatorRightIdx = i + 1;
5139 if (squareBracketsCount < 0) {
5140 _Console::printLine(
"MinitScript::" + callerMethod +
"(): " + (subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": unexpected char: ']'");
5146 if (haveKey ==
true) accessOperatorRightIdx = variableStatement.size();
5151 inline bool MinitScript::evaluateAccess(
const string& variableStatement,
const string& callerMethod, string::size_type& arrayAccessOperatorLeftIdx, string::size_type& arrayAccessOperatorRightIdx, int64_t& arrayIdx,
string& key,
const SubStatement* subStatement) {
5153 arrayIdx = ARRAYIDX_NONE;
5155 if (variableStatement.data()[arrayAccessOperatorLeftIdx] ==
'.') {
5156 key = string(
_StringTools::viewTrim(string_view(&variableStatement.data()[arrayAccessOperatorLeftIdx + 1], arrayAccessOperatorRightIdx - arrayAccessOperatorLeftIdx - 1)));
5160 auto arrayIdxExpressionStringView =
_StringTools::viewTrim(string_view(&variableStatement.data()[arrayAccessOperatorLeftIdx + 1], arrayAccessOperatorRightIdx - arrayAccessOperatorLeftIdx - 2));
5161 if (arrayIdxExpressionStringView.empty() ==
false) {
5168 auto evaluateStatement = string(arrayIdxExpressionStringView);
5169 if (evaluateInternal(evaluateStatement, evaluateStatement, statementReturnValue,
false) ==
false || statementReturnValue.
getIntegerValue(arrayIdx,
false) ==
false) {
5170 _Console::printLine(
"MinitScript::" + callerMethod +
"(): " + (subStatement !=
nullptr?getSubStatementInformation(*subStatement):scriptFileName) +
": Variable: " + variableStatement +
": failed to evaluate expression: '" +
string(arrayIdxExpressionStringView) +
"'");
5175 arrayIdx = ARRAYIDX_ADD;
5181 void MinitScript::setConstantInternal(
Variable& variable) {
5187 if (arrayPointer ==
nullptr)
break;
5188 for (
const auto arrayEntry: *arrayPointer) {
5189 setConstant(*arrayEntry);
5197 if (mapPointer ==
nullptr)
break;
5198 for (
const auto& [mapKey, mapValue]: *mapPointer) {
5199 setConstant(*mapValue);
5209 void MinitScript::unsetConstantInternal(
Variable& variable) {
5211 _Console::printLine(
"MinitScript::unsetConstantInternal(): Can not unset constant if reference variable is given.");
5219 if (arrayPointer ==
nullptr)
break;
5220 for (
const auto arrayEntry: *arrayPointer) {
5221 unsetConstant(*arrayEntry);
5229 if (mapPointer ==
nullptr)
break;
5230 for (
const auto& [mapKey, mapValue]: *mapPointer) {
5231 unsetConstant(*mapValue);
5241 void MinitScript::garbageCollection() {
5242 auto garbageCollectionDataTypesIndicesCopy = garbageCollectionDataTypesIndices;
5243 for (
auto index: garbageCollectionDataTypesIndicesCopy) {
5244 auto& garbageCollectionDataType = garbageCollectionDataTypes[index];
5245 garbageCollectionDataType.dataType->garbageCollection(garbageCollectionDataType.context);
static auto abs(auto value)
Returns absolute value.
MinitScript script application methods.
MinitScript script array methods.
MinitScript script base methods.
MinitScript script byte array methods.
MinitScript script console methods.
MinitScript script context methods.
MinitScript script cryptography methods.
MinitScript script file system methods.
MinitScript script JSON methods.
MinitScript script map methods.
MinitScript math methods.
void setType(MinitScript::VariableType type)
Set type.
virtual const vector< string > & getContextFunctions()
const vector< ArgumentType > & getArgumentTypes() const
virtual const string getMethodName()=0
virtual const string getName()=0
const Statement & getStatement() const
const SyntaxTreeNode * getSyntaxTree() const
void copy(Initializer *initializer)
Copy from initializer.
bool isPrivateScope() const
void unsetConstant()
Unset constant.
InitializerReferenceUnion initializerReferenceUnion
bool getIntegerValue(int64_t &value, bool optional=false) const
Get integer value from given variable.
void setImplicitTypedValueFromStringView(const string_view &value, MinitScript *minitScript, int scriptIdx, const Statement &statement)
Set implicit typed value given by value string.
void setConstant()
Set constant.
bool getStackletValue(string &stacklet, int &scriptIdx, bool optional=false) const
Get stacklet values from given variable.
const string getAsString() const
VariableType getType() const
void setFunctionAssignment(const string &function, int scriptIdx=MinitScript::SCRIPTIDX_NONE)
Set function assignment from given value into variable.
const unordered_map< string, Variable * > * getMapPointer() const
static const string & getTypeAsString(VariableType type)
Returns given variable type as string.
unordered_map< string, Variable * > & getMapValueReference()
void setMapEntry(const string &key, const Variable &value, bool _private=false)
Set entry in map with given key.
vector< Variable * > & getArrayValueReference()
void insertSetKey(const string &key)
Insert given key in set.
void pushArrayEntry(const Variable &value)
Push entry to array.
void setStackletAssignment(const string &stacklet, int scriptIdx=MinitScript::SCRIPTIDX_NONE)
Set stacklet assignment from given value into variable.
unordered_set< string > & getSetValueReference()
const vector< Variable * > * getArrayPointer() const
bool getBooleanValue(bool &value, bool optional=false) const
Get boolean value from given variable.
Initializer * getInitializer() const
Return initializer.
const string getValueAsString(bool formatted=false, bool jsonCompatible=false, int depth=0) const
Print string representation of variable.
void setReference(const Variable *variable)
Set reference.
void setType(VariableType newType)
Set type.
void removeSetKey(const string &key)
Remove key in set with given key.
bool getFunctionValue(string &function, int &scriptIdx, bool optional=false) const
Get function values from given variable.
void setValue(const Variable &variable)
Set value from given variable into variable.
bool parseStatement(const string_view &executableStatement, string_view &methodName, vector< ParserArgument > &arguments, const Statement &statement, string &accessObjectMemberStatement)
Parse a statement.
void setScriptStateState(int state)
Set script state machine state.
const string getStatementInformation(const Statement &statement, int subLineIdx=-1)
Return statement information.
void createLamdaFunction(Variable &variable, const vector< string_view > &arguments, const string_view &functionScriptCode, int lineIdx, bool populateThis, const Statement &statement, const string &nameHint=string())
vector< string > enabledNamedConditions
int64_t timeEnabledConditionsCheckLast
void resetScriptExecutationState(int scriptIdx, StateMachineStateId stateMachineState)
Reset script execution state.
ScriptState & getScriptState()
bool createStatementSyntaxTree(int scriptIdx, const string_view &methodName, const vector< ParserArgument > &arguments, const Statement &statement, SyntaxTreeNode &syntaxTree, int subLineIdx=0)
Create statement syntax tree.
virtual int determineScriptIdxToStart()
Determine script index to start.
void executeNextStatement()
Execute next statement.
MinitScript script network methods.
MinitScript script script methods.
MinitScript script set methods.
MinitScript script string methods.
MinitScript script time methods.
MinitScript script xml methods.
static const string getContentAsString(const string &pathName, const string &fileName)
Get content as string.
static void sleep(const uint64_t milliseconds)
sleeps current thread for given time in milliseconds
static bool isSpace(uint32_t character)
Returns if character is a white space.
static bool isAlphaNumeric(uint32_t character)
Returns if character is alpha numeric.
static void printLine()
Print newline to console.
static void initialize()
Initialize.
static void print(const string_view &str)
Print given string without trainling newline to console.
static bool viewIs(const string_view &str)
Check if given string is a integer string.
static int viewParse(const string_view &str)
Parse integer.
static const string encode(const string &decodedString)
Encodes an string to SHA256 string.
static int64_t getCurrentMillis()
Retrieve current time in milliseconds.
unordered_map< string, Variable * > variables
vector< Block > blockStack
StateMachineState * lastStateMachineState
Method * getMethod() const
vector< SyntaxTreeNode > arguments
void setMethod(Method *method)
Set method.
int64_t getScriptIdx() const
void setScriptIdx(uint64_t scriptIdx)
Set function/stacklet script index.
Initializer * initializer