#include #include #include #define DEVELOPER_MESSAGES false #define EXAMPLE_PROJECT false #define NAMEVERSION "ZSharp v2.1.0-alpha" #if defined(__unix__) #define UNIX true #define WINDOWS false #elif defined(_MSC_VER) #define UNIX false #define WINDOWS true #endif #include #include #include #include #include #include #include #include #include #include #if UNIX #include #include #elif WINDOWS #include #endif #include "eval.h" #include "strops.h" #include "builtin.h" #include "main.h" #include "anyops.h" #include "ZS.h" using namespace std; using namespace boost; unordered_map globalVariableValues; unordered_map>> functionValues; boost::any GetVariableValue(const string& varName, const unordered_map& variableValues) { string classSubComponent; string baseName = trim(varName); if (count(varName, '.') > 0) { classSubComponent = trim(varName.substr(indexInStr(varName, '.') + 1, -1)); baseName = trim(split(varName, '.')[0]); } boost::any outputValue = nullType; auto iA = variableValues.find(baseName); auto iB = globalVariableValues.find(baseName); if (iA != variableValues.end()) outputValue = iA->second; else if (iB != globalVariableValues.end()) outputValue = iB->second; else outputValue = varName; if (count(varName, '.') > 0 && !outputValue.empty()) return GetClassSubComponent(outputValue, classSubComponent); else return outputValue; } // Check if there is a variable with the specified name bool IsVar(const string& varName, const unordered_map& variableValues) { if (variableValues.find(split(varName, '.')[0]) != variableValues.end() && split(varName, '.')[0] != "ZS") return true; else return false; } // Return a vector of values that correspond to a vector of input variable names vector VarValues(const vector& varNames, unordered_map& variableValues) { vector realValues; for (int varIndex = 0; varIndex < varNames.size(); varIndex++) { string varName = trim(varNames.at(varIndex)); //realValues.push_back(EvalExpression(varName, variableValues)); auto iA = variableValues.find(varName); if (iA != variableValues.end()) { realValues.push_back(iA->second); } else { auto iB = globalVariableValues.find(varName); if (iB != globalVariableValues.end()) realValues.push_back(iB->second); else realValues.push_back(EvalExpression(varName, variableValues)); } } return realValues; } bool IsFunction(const string& funcName) { if (functionValues.find(funcName) != functionValues.end()) return true; else return false; } bool IsZSFunction(const string& funcName) { if (funcName[0] == 'Z' && funcName[1] == 'S' && funcName[2] == '.') return true; else return false; } boost::any EvalExpression(const string& ex, unordered_map& variableValues) { string expression = trim(ex); bool inQuotes = false; #if DEVELOPER_MESSAGES == true //InterpreterLog(" old expression: |" + expression + "|"); #endif bool isFunc = IsFunction(split(expression, '(')[0]); bool isZS = split(expression, '.')[0] == "ZS"; // If no operations are applied, then return self if ((countOutsideParenthesis(expression, '+') == 0 && countOutsideParenthesis(expression, '-') == 0 && countOutsideParenthesis(expression, '*') == 0 && countOutsideParenthesis(expression, '/') == 0 && countOutsideParenthesis(expression, '^') == 0) || split(expression, '.')[0] == "ZS") { //bool isFunc = IsFunction(split(expression, '(')[0]); if (isFunc && !inQuotes) { // start -> FuncCall(0, x, OtherFunc(a)) // changeto -> 0, x, OtherFunc(a) string insideFunArgs = betweenChars(expression, '(', ')'); #if DEVELOPER_MESSAGES == true cout << insideFunArgs << endl; #endif vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); #if DEVELOPER_MESSAGES == true cout << "[" << unWrapVec(argList) << "]" << endl; #endif vector funcArgs = VarValues(argList, variableValues); return ExecuteFunction(trim(split(expression, '(')[0]), funcArgs); } else if (isZS && !inQuotes) { // start -> FuncCall(0, x, OtherFunc(a)) // changeto -> 0, x, OtherFunc(a) string insideFunArgs = betweenChars(expression, '(', ')'); #if DEVELOPER_MESSAGES == true cout << insideFunArgs << endl; #endif vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); #if DEVELOPER_MESSAGES == true cout << "[" << unWrapVec(argList) << "]" << endl; #endif vector funcArgs = VarValues(argList, variableValues); return ZSFunction(trim(split(expression, '(')[0]), funcArgs); } else return GetVariableValue(expression, variableValues); } string newExpression = ""; inQuotes = false; for (int i = 0; i < expression.size(); i++) { if (expression[i] == '\"' && !isEscaped(newExpression, i)) inQuotes = !inQuotes; if (isalpha(expression[i]) || expression[i] == '_') { string name = ""; while (i < expression.size() && (isalpha(expression[i]) || expression[i] == '.' || expression[i] == '_')) { name += expression[i]; i++; } //string varVal = GetVariableValue(name, variables, variableValues); bool isFunc = IsFunction(name); if (isFunc && !inQuotes) { // start -> FuncCall(0, x, OtherFunc(a)) // changeto -> 0, x, OtherFunc(a) string insideFunArgs = betweenChars(expression, '(', ')'); #if DEVELOPER_MESSAGES == true cout << insideFunArgs << endl; #endif vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); #if DEVELOPER_MESSAGES == true cout << unWrapVec(argList) << endl; #endif vector funcArgs = VarValues(argList, variableValues); string returnVal = AnyAsString(ExecuteFunction(trim(split(expression, '(')[0]), funcArgs)); newExpression += returnVal; } else if (split(name, '.')[0] == "ZS" && !inQuotes) { // start -> FuncCall(0, x, OtherFunc(a)) // changeto -> 0, x, OtherFunc(a) string insideFunArgs = betweenChars(expression, '(', ')'); #if DEVELOPER_MESSAGES == true cout << insideFunArgs << endl; #endif vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); #if DEVELOPER_MESSAGES == true cout << unWrapVec(argList) << endl; #endif vector funcArgs = VarValues(argList, variableValues); string returnVal = AnyAsString(ExecuteFunction(trim(split(expression, '(')[0]), funcArgs)); newExpression += returnVal; } else { if (inQuotes) newExpression += name; else newExpression += AnyAsString(GetVariableValue(name, variableValues)); } i--; } else { newExpression += expression[i]; } } #if DEVELOPER_MESSAGES == true //InterpreterLog(" new expression: |" + newExpression + "|"); #endif bool addStrings = false; for (int i = 0; i < (int)newExpression.size(); i++) if (isalpha(newExpression[i]) || (newExpression[i] == '\"' && !isEscaped(newExpression, i))) { addStrings = true; break; } if (addStrings) { inQuotes = false; string withoutParenthesis = ""; for (int i = 0; i < (int)newExpression.size(); i++) { if (newExpression[i] == '\"' && !isEscaped(newExpression, i)) { inQuotes = !inQuotes; continue; } if (inQuotes) withoutParenthesis += newExpression[i]; if (!inQuotes && newExpression[i] != '(' && newExpression[i] != ')' && newExpression[i] != '+' && newExpression[i] != ' ') withoutParenthesis += newExpression[i]; } //cout << "NewSTRING = " << Quoted(withoutParenthesis) << endl; return withoutParenthesis; } else return evaluate(newExpression); } bool BooleanLogic(const string& valA, const string& determinant, const string& valB, unordered_map& variableValues) { boost::any valARealValue; boost::any valBRealValue; if(valA != "") valARealValue = EvalExpression(valA, variableValues); if(valB != "") valBRealValue = EvalExpression(valB, variableValues); #if DEVELOPER_MESSAGES == true InterpreterLog(AnyAsString(valARealValue) + " " + determinant + " " + AnyAsString(valBRealValue) + " : " + AnyAsString(valA) + " " + determinant + " " + AnyAsString(valB) + " : " + to_string(AnyAsString(valARealValue) == AnyAsString(valBRealValue))); #endif if (determinant == "==") return any_compare(valARealValue, valBRealValue); else if (determinant == "!=") return !any_compare(valARealValue, valBRealValue); else if (determinant == ">=") return AnyAsFloat(valARealValue) >= AnyAsFloat(valBRealValue); else if (determinant == "<=") return AnyAsFloat(valARealValue) <= AnyAsFloat(valBRealValue); else if (determinant == ">") return AnyAsFloat(valARealValue) > AnyAsFloat(valBRealValue); else if (determinant == "<") return AnyAsFloat(valARealValue) < AnyAsFloat(valBRealValue); else if (determinant == "") return AnyAsBool(valARealValue) == true; else LogWarning("unrecognized determinant \'" + determinant + "\'"); return false; } int varOperation(const vector& str, unordered_map& variableValues) { if (IsVar(str.at(0), variableValues)) { // Checks if type is simple, like int or string if (any_type(variableValues[str.at(0)]) <= 3) { if (str.at(1) == "=") variableValues[str.at(0)] = EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues); else if (str.at(1) == "+=") variableValues[str.at(0)] = EvalExpression(str.at(0) + "+(" + unWrapVec(vector(str.begin() + 2, str.end())) + ")", variableValues); else if (str.at(1) == "-=") variableValues[str.at(0)] = AnyAsFloat(variableValues[str.at(0)]) - AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else if (str.at(1) == "*=") variableValues[str.at(0)] = AnyAsFloat(variableValues[str.at(0)]) * AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else if (str.at(1) == "/=") variableValues[str.at(0)] = AnyAsFloat(variableValues[str.at(0)]) / AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else LogWarning("unrecognized operator \'" + str.at(1) + "\'"); } // Else it is a Vec2. No other complex class can be operated on it's base form (ex. you can't do: Sprite += Sprite) else if (any_type(variableValues[str.at(0)]) == 5) { boost::any otherExpression = EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues); if (str.at(1) == "=") variableValues[str.at(0)] = otherExpression; else if (str.at(1) == "+=") variableValues[str.at(0)] = AnyAsVec2(variableValues[str.at(0)]) + AnyAsVec2(otherExpression); else if (str.at(1) == "-=") variableValues[str.at(0)] = AnyAsVec2(variableValues[str.at(0)]) - AnyAsVec2(otherExpression); else if (str.at(1) == "*=") variableValues[str.at(0)] = AnyAsVec2(variableValues[str.at(0)]) * AnyAsFloat(otherExpression); else if (str.at(1) == "/=") variableValues[str.at(0)] = AnyAsVec2(variableValues[str.at(0)]) / AnyAsFloat(otherExpression); else LogWarning("unrecognized operator \'" + str.at(1) + "\'"); } return 0; } else if (IsVar(str.at(0), globalVariableValues)) { // Checks if type is simple, like int or string if (any_type(globalVariableValues[str.at(0)]) <= 3) { if (str.at(1) == "=") globalVariableValues[str.at(0)] = EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues); else if (str.at(1) == "+=") globalVariableValues[str.at(0)] = EvalExpression(str.at(0) + "+(" + unWrapVec(vector(str.begin() + 2, str.end())) + ")", variableValues); else if (str.at(1) == "-=") globalVariableValues[str.at(0)] = AnyAsFloat(globalVariableValues[str.at(0)]) - AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else if (str.at(1) == "*=") globalVariableValues[str.at(0)] = AnyAsFloat(globalVariableValues[str.at(0)]) * AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else if (str.at(1) == "/=") globalVariableValues[str.at(0)] = AnyAsFloat(globalVariableValues[str.at(0)]) / AnyAsFloat(EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues)); else LogWarning("unrecognized operator \'" + str.at(1) + "\'"); } // Else it is a Vec2. No other complex class can be operated on it's base form (ex. you can't do: Sprite += Sprite) else if (any_type(globalVariableValues[str.at(0)]) == 5) { boost::any otherExpression = EvalExpression(unWrapVec(vector(str.begin() + 2, str.end())), variableValues); if (str.at(1) == "=") globalVariableValues[str.at(0)] = otherExpression; else if (str.at(1) == "+=") globalVariableValues[str.at(0)] = AnyAsVec2(globalVariableValues[str.at(0)]) + AnyAsVec2(otherExpression); else if (str.at(1) == "-=") globalVariableValues[str.at(0)] = AnyAsVec2(globalVariableValues[str.at(0)]) - AnyAsVec2(otherExpression); else if (str.at(1) == "*=") globalVariableValues[str.at(0)] = AnyAsVec2(globalVariableValues[str.at(0)]) * AnyAsFloat(otherExpression); else if (str.at(1) == "/=") globalVariableValues[str.at(0)] = AnyAsVec2(globalVariableValues[str.at(0)]) / AnyAsFloat(otherExpression); else LogWarning("unrecognized operator \'" + str.at(1) + "\'"); } return 0; } LogWarning("uninitialized variable or typo in \'" + str.at(0) + "\'"); return 1; } boost::any ProcessLine(const vector>& words, int& lineNum, unordered_map& variableValues) { // Check if the first two chars are '//', which would make it a comment if (startsWith(words.at(lineNum).at(0), "//")) return nullType; // If print statement (deprecated, now use ZS.System.Print() function) else if (words.at(lineNum).at(0) == "print") { cout << StringRaw(AnyAsString(EvalExpression(unWrapVec(vector(words.at(lineNum).begin() + 1, words.at(lineNum).end())), variableValues))) << endl; return nullType; } // Check if it is a function return else if (words.at(lineNum).at(0) == "return") return EvalExpression(unWrapVec(vector(words.at(lineNum).begin() + 1, words.at(lineNum).end())), variableValues); // Check if it is ZS Builtin function else if (words.at(lineNum).at(0)[0] == 'Z' && words.at(lineNum).at(0)[1] == 'S' && words.at(lineNum).at(0)[2] == '.') return EvalExpression(unWrapVec(words.at(lineNum)), variableValues); // Check if it is function else if (IsFunction(trim(split(words.at(lineNum).at(0), '(')[0]))) { // No args provided if (count(words.at(lineNum).at(0), '(') > 0 && count(words.at(lineNum).at(0), ')') > 0) ExecuteFunction(trim(split(words.at(lineNum).at(0), '(')[0]), vector()); else { // Args provided, parse them first // start -> FuncCall(0, x, OtherFunc(a)) // changeto -> 0, x, OtherFunc(a) string insideFunArgs = betweenChars(unWrapVec(words.at(lineNum)), '(', ')'); vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); vector funcArgs = VarValues(argList, variableValues); ExecuteFunction(trim(split(words.at(lineNum).at(0), '(')[0]), funcArgs); } return nullType; } // Check if it is a SplitThread call else if (startsWith(words.at(lineNum).at(0), "SplitThread")) { vector lineContents = removeTabs(words.at(lineNum), 10); cout << "New Thread: " << words.at(lineNum).at(0) << endl; //lineContents.at(0) = betweenChars(lineContents.at(0), '(', ')'); //cout << "debug: " << lineContents.at(0) << endl; //if (betweenChars(lineContents.at(0), '(', ')') == "") // std::thread thread_obj(ExecuteFunction, trim(split(lineContents.at(0), '(')[0]), vector()); //else // std::thread thread_obj(ExecuteFunction, trim(split(lineContents.at(0), '(')[0]), VarValues(split(RMParenthesis("(" + split(unWrapVec(rangeInVec(lineContents, 0, (int)lineContents.size() - 2)), '(')[1]), ','), variableValues)); return nullType; } // Check if global variable declaration else if (trim(words.at(lineNum).at(0)) == "global") { globalVariableValues[words.at(lineNum).at(2)] = EvalExpression(unWrapVec(slice(words.at(lineNum), 4, -1)), variableValues); return nullType; } // Iterate through all types to see if line inits or // re-inits a variable then store it with it's value else if (countInVector(types, trim(words.at(lineNum).at(0))) > 0) { //cout << words.at(lineNum).at(1) << "=" << unWrapVec(slice(words.at(lineNum), 3, -1)) << "=" << AnyAsString(EvalExpression(unWrapVec(slice(words.at(lineNum), 3, -1)), variableValues)) << endl; variableValues[words.at(lineNum).at(1)] = EvalExpression(unWrapVec(slice(words.at(lineNum), 3, -1)), variableValues); return nullType; } // Check existing variables: If matches, then it means // the variables value is getting changed with an operator else if (count(words.at(lineNum).at(0), '.') == 0 && (IsVar(words.at(lineNum).at(0), variableValues) || IsVar(words.at(lineNum).at(0), globalVariableValues))) { // Evaluates what the operator (ex. '=', '+=') does to the value on the left by the value on the right varOperation(vector(words.at(lineNum).begin(), words.at(lineNum).end()), variableValues); return nullType; } // Check existing variables: To see if accessing class sub component else if (count(words.at(lineNum).at(0), '.') > 0 && IsVar(split(words.at(lineNum).at(0), '.')[0], variableValues) || IsVar(split(words.at(lineNum).at(0), '.')[0], globalVariableValues)) { if (IsVar(split(words.at(lineNum).at(0), '.')[0], variableValues)) variableValues[split(words.at(lineNum).at(0), '.')[0]] = EditClassSubComponent(variableValues[split(words.at(lineNum).at(0), '.')[0]], words.at(lineNum).at(1), EvalExpression(unWrapVec(vector(words.at(lineNum).begin() + 2, words.at(lineNum).end())), variableValues), split(words.at(lineNum).at(0), '.')[1]); else if (IsVar(split(words.at(lineNum).at(0), '.')[0], globalVariableValues)) globalVariableValues[split(words.at(lineNum).at(0), '.')[0]] = EditClassSubComponent(globalVariableValues[split(words.at(lineNum).at(0), '.')[0]], words.at(lineNum).at(1), EvalExpression(unWrapVec(vector(words.at(lineNum).begin() + 2, words.at(lineNum).end())), variableValues), split(words.at(lineNum).at(0), '.')[1]); return nullType; } // If declaring a while loop, loop until false else if (words.at(lineNum).at(0) == "while") { vector> whileContents; vector whileParameters; // Gather the parameters that must be == true for the loop to run int numOfBrackets = 0; for (int w = 1; w < (int)words.at(lineNum).size(); w++) { if (count(words.at(lineNum).at(w), '{') == 0) whileParameters.push_back(words.at(lineNum)[w]); else { whileParameters.push_back(replace(words.at(lineNum)[w], "{", "")); numOfBrackets = 1; break; } } // If the statement is already false, don't bother gathering the contents if(BooleanLogic(whileParameters.at(0), whileParameters.at(1), whileParameters.at(2), variableValues) == false){ lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; lineNum++; } return nullType; } // Gather the contents lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; whileContents.push_back(words.at(lineNum)); lineNum++; } whileContents = removeTabsWdArry(whileContents, 1); // Loop while true while (BooleanLogic(whileParameters.at(0), whileParameters.at(1), whileParameters.at(2), variableValues)) { //Iterate through all lines in while loop for (int lineNum = 0; lineNum < (int)whileContents.size(); lineNum++) { if(startsWith(whileContents.at(0).at(0), "continue")) break; // Stops iterating through lines and return to beginning if(startsWith(whileContents.at(0).at(0), "break")) return nullType; // Stops iterating through lines and leave while loop boost::any returnVal = ProcessLine(whileContents, lineNum, variableValues); if (!returnVal.empty()) return returnVal; } } return nullType; } // If declaring an if statement, only execute if true else if (words.at(lineNum).at(0) == "if") { vector> ifContents; vector ifParameters; // Gather the parameters that must be == true for the loop to run int numOfBrackets = 0; for (int w = 1; w < (int)words.at(lineNum).size(); w++) { if (count(words.at(lineNum).at(w), '{') == 0) ifParameters.push_back(words.at(lineNum)[w]); else { ifParameters.push_back(replace(words.at(lineNum)[w], "{", "")); numOfBrackets = 1; break; } } // If the statement is already false, don't bother gathering the contents if(BooleanLogic(ifParameters.at(0), ifParameters.at(1), ifParameters.at(2), variableValues) == false){ lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; lineNum++; } return nullType; } // Gather the contents lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; ifContents.push_back(words.at(lineNum)); lineNum++; } ifContents = removeTabsWdArry(ifContents, 1); // Execute if true if (BooleanLogic(ifParameters.at(0), ifParameters.at(1), ifParameters.at(2), variableValues)) { //Iterate through all lines in if statement for (int l = 0; l < (int)ifContents.size(); l++) { if(startsWith(ifContents.at(0).at(0), "break")) return nullType; // Stops iterating through lines and leave while loop boost::any returnVal = ProcessLine(ifContents, l, variableValues); if (!returnVal.empty()) return returnVal; } } else if (words.size() > lineNum) { if (words[lineNum].at(0) == "else") { vector> elseContents; vector elseParameters; int numOfBrackets = 0; for (int w = 1; w < (int)words.at(lineNum).size(); w++) { if (count(words.at(lineNum).at(w), '{') != 0) { numOfBrackets = 1; break; } } lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; elseContents.push_back(words.at(lineNum)); lineNum++; } elseContents = removeTabsWdArry(elseContents, 1); //Iterate through all lines in else statement for (int l = 0; l < (int)elseContents.size(); l++) { boost::any returnVal = ProcessLine(elseContents, l, variableValues); if (!returnVal.empty()) return returnVal; } } } return nullType; } return nullType; } boost::any ExecuteFunction(const string& functionName, const vector& inputVarVals) { // Get contents of function from global function map std::vector> words = functionValues[functionName]; unordered_map variableValues = {}; std::vector funcArgs = words.at(0); // Set function variables equal to whatever inputs were provided for (int i = 0; i < (int)inputVarVals.size(); i++) { if (i < funcArgs.size()) { variableValues[funcArgs[i]] = inputVarVals[i]; #if DEVELOPER_MESSAGES == true cout << functionName + " \x1B[33m" << funcArgs[i] << " == " << AnyAsString(inputVarVals[i]) << "\033[0m\t\t" << endl; #endif } } //Iterate through all lines in function for (int lineNum = 1; lineNum < (int)words.size(); lineNum++) { try { boost::any returnVal = ProcessLine(words, lineNum, variableValues); if (!returnVal.empty()) return returnVal; } catch (const std::exception&) { } } return nullType; } int parseZSharp(string script) { //script = replace(script, " ", "\t"); // Replace spaces with tabs (not really required, and will break purposefull whitespace in strings etc.) #if DEVELOPER_MESSAGES InterpreterLog("Contents:\n" + script); #endif // Split the script by ;, signifying a line ending vector lines = split(script, '\n'); for (int i = 0; i < (int)lines.size(); i++){ // Then split said lines into indiviual words if((lines.at(i)[0] == "/" && lines.at(i)[1] == "/") || trim(lines.at(i)) == "") { // Remove line if it is a comment or if it is blank lines.erase(lines.begin() + i); } } vector> words; for (int i = 0; i < (int)lines.size(); i++) // Then split said lines into indiviual words words.push_back(split(lines.at(i), ' ')); #if DEVELOPER_MESSAGES InterpreterLog("Gather variables & functions..."); #endif // Go through entire script and iterate through all types to see if line is a variable // or function declaration, then store it with it's value for (int lineNum = 0; lineNum < (int)words.size(); lineNum++) { //Checks if it is function if (words.at(lineNum).at(0) == "func") { vector> functionContents; string functName = split(words.at(lineNum).at(1), '(')[0]; #if DEVELOPER_MESSAGES == true InterpreterLog("Load script function " + functName + "..."); #endif string args = ""; if (indexInStr(unWrapVec(words.at(lineNum)), ')') - indexInStr(unWrapVec(words.at(lineNum)), '(') > 1) for (int w = 1; w < (int)words.at(lineNum).size(); w++) // Get all words from the instantiation line: these are the args { if (count(words.at(lineNum).at(w), '{') == 0) args += replace(replace(words.at(lineNum).at(w), "(", " "), ")", ""); } args = trim(replace(args, functName + " ", "")); functionContents.push_back(split(args, ',')); int numOfBrackets = 0; for (int w = 1; w < (int)words.at(lineNum).size(); w++) { if (count(words.at(lineNum).at(w), '{') != 0) { numOfBrackets = 1; break; } } for (int p = lineNum + 1; p < (int)words.size(); p++) { numOfBrackets += countInVector(words.at(p), "{") - countInVector(words.at(p), "}"); if (numOfBrackets == 0) break; functionContents.push_back(removeTabs(words.at(p), 1)); } functionValues[functName] = functionContents; } else { if (words.at(lineNum).at(0) == "include") { string scriptPath = StringRaw(words.at(lineNum).at(1)); string scriptTextContents; #if DEVELOPER_MESSAGES == true InterpreterLog("Including from " + words.at(lineNum).at(1) + "..."); #endif #if UNIX // Get script contents as single string auto ss = ostringstream{}; ifstream input_file(scriptPath); ss << input_file.rdbuf(); scriptTextContents = ss.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); #endif #elif WINDOWS // Get script contents as single string ifstream script(scriptPath); stringstream scriptString; scriptString << script.rdbuf(); scriptTextContents = scriptString.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); #endif #endif parseZSharp(scriptTextContents); } else if (words.at(lineNum).at(0) == "string") { globalVariableValues[words.at(lineNum).at(1)] = StringRaw(words.at(lineNum).at(3)); #if DEVELOPER_MESSAGES == true InterpreterLog("Load script variable " + words.at(lineNum).at(1) + "..."); #endif } else if (words.at(lineNum).at(0) == "int") { globalVariableValues[words.at(lineNum).at(1)] = stoi(words.at(lineNum).at(3)); #if DEVELOPER_MESSAGES == true InterpreterLog("Load script variable " + words.at(lineNum).at(1) + "..."); #endif } else if (words.at(lineNum).at(0) == "float") { globalVariableValues[words.at(lineNum).at(1)] = stof(words.at(lineNum).at(3)); #if DEVELOPER_MESSAGES == true InterpreterLog("Load script variable " + words.at(lineNum).at(1) + "..."); #endif } else if (words.at(lineNum).at(0) == "bool") { globalVariableValues[words.at(lineNum).at(1)] = stob(words.at(lineNum).at(3)); #if DEVELOPER_MESSAGES == true InterpreterLog("Load script variable " + words.at(lineNum).at(1) + "..."); #endif } /*else LogWarning("unrecognized type \'" + words.at(lineNum).at(0) + "\' on line: " + to_string(lineNum));*/ } } return 0; } int main(int argc, char* argv[]) { // Print the name of the interpreter and it's version in inverted black on white text PrintColored(NAMEVERSION, blackFGColor, whiteBGColor, false); cout << endl << endl; // Gathers builtin functions and variables GetBuiltins(ZSContents); functionValues = builtinFunctionValues; globalVariableValues = builtinVarVals; std::string scriptTextContents; // If scriptname is supplied and not in developer mode if (argc > 1 || EXAMPLE_PROJECT) { std::string scriptPath; if (EXAMPLE_PROJECT) scriptPath = "D:\\Code\\Z-Sharp\\Releases\\ZS-Win-x64-Base\\Pong-Example-Project\\script.zs"; else scriptPath = argv[1]; #if DEVELOPER_MESSAGES cout << scriptPath << endl; #endif if (!fileExists(scriptPath)) LogCriticalError("Failed to load script from path: \"" + scriptPath + "\""); std::string projectDirectory = scriptPath.substr(0, scriptPath.find_last_of("/\\")); #if UNIX // Get script contents as single string auto ss = ostringstream{}; ifstream input_file(scriptPath); ss << input_file.rdbuf(); scriptTextContents = ss.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); #endif // Change the current working directory to that of the script int chErr = chdir(projectDirectory.c_str()); if (chErr < 0) LogCriticalError("Failed to change directory to: \"" + projectDirectory + "\", error num: " + to_string(chErr)); #if DEVELOPER_MESSAGES InterpreterLog("Changed directory to " + projectDirectory + "..."); #endif #elif WINDOWS // Get script contents as single string ifstream script(scriptPath); stringstream scriptString; scriptString << script.rdbuf(); scriptTextContents = scriptString.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); #endif // Change the current working directory to that of the script std::wstring_convert> converter; std::wstring wide = converter.from_bytes(projectDirectory); LPCWSTR s = wide.c_str(); SetCurrentDirectory(s); #if DEVELOPER_MESSAGES InterpreterLog("Changed directory to " + projectDirectory + "..."); #endif #endif } else { // If no script is provided as an argument throw error LogWarning("No script provided! Please drag and drop .ZS file over interpreter executable file, or provide it's path as a command-line argument."); cout << "Press Enter to Continue"; cin.ignore(); exit(1); } #if DEVELOPER_MESSAGES InterpreterLog("Parsing..."); #endif // Parse the script parseZSharp(scriptTextContents); #if DEVELOPER_MESSAGES InterpreterLog("Start Main()"); #endif try { // Executes main, which is the entry point function ExecuteFunction("Main", vector {}); } catch (const std::exception&) { //Failed with error } // Entire script has been run, exit. #if DEVELOPER_MESSAGES // If built with developer messages, then verify exit cout << "Press Enter to Continue"; cin.ignore(); exit(1); #else if (argc > 2) { string a = argv[2]; std::transform(a.begin(), a.end(), a.begin(), [](unsigned char c) { return std::tolower(c); }); if (a == "-ve") // If the '-ve' (verify exit) option is used, ask for verification on exit { cout << "Press Enter to Continue"; cin.ignore(); exit(1); } } #endif // Else exit automatically return 0; }