Browse Source

jsIsFalse() func support, doFunctionCall=>jsFunctionCall, doExpression() multiple char fixes / || support, doAssignment() trim tokens/add stack/better && handling, dereferenceHasBase(), jsParseTokens() fix if condition result

master
Odilitime 2 years ago
parent
commit
a50a1129bd
1 changed files with 140 additions and 55 deletions
  1. 140
    55
      src/parsers/scripting/javascript/JSParser.cpp

+ 140
- 55
src/parsers/scripting/javascript/JSParser.cpp View File

@@ -1,4 +1,5 @@
#include "JSParser.h"
#include "BrowserJS.h"
#include "../../../tools/StringUtils.h"

#include <iostream>
@@ -42,9 +43,11 @@ bool jsIsFalse(js_internal_storage *generic) {
js_number *jnum = dynamic_cast<js_number*>(generic);
return !jnum->value;
} else
if (type == "bool") {
if (type == "bool") {
js_bool *jb = dynamic_cast<js_bool*>(generic);
return !jb->value;
} else if (type == "func") {
return false; // func are always true
} else
//if (type == "unknown") {
// why is this needed?
@@ -280,12 +283,16 @@ std::vector<std::string> jsGetTokens(const std::string &source, const size_t sta
return tokens;
}

js_internal_storage *doFunctionCall(js_function *func, std::string params, js_function &scope) {
if (func == nullptr) {
std::cout << "passed null into doFunctionCall\n";
return nullptr;
js_internal_storage *jsFunctionCall(std::string funcName, js_function *func, std::string params, js_function &scope) {
if (isConstruct(funcName)) {
return executeConstruct(funcName, params, scope);
} else {
if (func == nullptr) {
std::cout << "passed null into jsFunctionCall\n";
return nullptr;
}
return jsParseTokens(func->tokens, &scope);
}
return jsParseTokens(func->tokens, &scope);
}

// this should evaluate an expression and return it's return value
@@ -361,7 +368,7 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
}
// ||
if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
expression_parts.push_back("||");
}
if (token[cursor] == '&' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
@@ -377,27 +384,27 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
expression_parts.push_back("<");
}
if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
expression_parts.push_back("<=");
}
if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
expression_parts.push_back(">=");
}
if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
expression_parts.push_back("==");
}
if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
expression_parts.push_back("===");
}
if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
expression_parts.push_back("!=");
}
if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
expression_parts.push_back("!==");
}
// +
@@ -407,7 +414,7 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
} else
if (token[cursor] == '-') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
expression_parts.push_back("+");
expression_parts.push_back("-");
} else
if (token[cursor] == '*') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
@@ -542,6 +549,9 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
// if stack is false abort
std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
std::string type = typeOfStorage(stack);
if (jsIsFalse(stack)) {
std::cout << "&& stack isFalse\n";
}
if (type=="string") {
js_string *string = dynamic_cast<js_string*>(stack);
std::cout << "stack points to [" << stack << "] value[" << string->value << "]\n";
@@ -573,6 +583,17 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
}
continue;
}
// ||
if (trimmedToken == "||") {
std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
std::string type = typeOfStorage(stack);
if (jsIsFalse(stack)) {
// stack is false, we have to execute next expression
continue;
}
// if stack is true, we don't need to evaulate the rest
std::cout << "No need to execute the rest of this expression\n";
}
if (trimmedToken == "!") {
state = 4;
continue;
@@ -622,20 +643,23 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
// variable
// object.property
js_internal_storage *dereferenceTest = dereferenceObject(trimmedToken, &rootScope);
if (dereferenceTest) {
if (typeOfStorage(dereferenceTest)=="func") {
// it could be a call...
callFuncName = it;
callFunc = dynamic_cast<js_function *>(dereferenceTest);
if (!callFunc) {
std::cout << "Couldnt cast deference to func\n";
bool deref = dereferenceHasBase(trimmedToken, &rootScope);
if (deref) {
js_internal_storage *dereferenceTest = dereferenceObject(trimmedToken, &rootScope);
if (dereferenceTest) {
if (typeOfStorage(dereferenceTest)=="func") {
// it could be a call...
callFuncName = it;
callFunc = dynamic_cast<js_function *>(dereferenceTest);
if (!callFunc) {
std::cout << "Couldnt cast deference to func\n";
}
state = 1;
} else {
stack = dereferenceTest;
}
state = 1;
} else {
stack = dereferenceTest;
continue;
}
continue;
}
// it's a string constant
@@ -688,8 +712,8 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
std::cout << "isVar [" << isVar << "]\n";
std::cout << "stack could be [" << *isVar << "] type[" << typeOfStorage(stack) << "]\n";
if (typeOfStorage(stack)=="func") {
callFuncName = it;
callFunc = dynamic_cast<js_function *>(dereferenceTest);
callFuncName = trimmedToken;
callFunc = dynamic_cast<js_function *>(stack);
state = 1;
// (
// 1
@@ -706,10 +730,15 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
} else {
js_internal_storage *scopeTest = jsLocateKey(&rootScope, it);
if (scopeTest) {
std::cout << "locatedKey stack[" << scopeTest << "] stackFalse[" << jsIsFalse(scopeTest) << "]\n";
stack = scopeTest;
} else {
jsDisplayScope(&rootScope, 0);
std::cout << "is Not a Var\n";
if (!deref) {
jsDisplayScope(&rootScope, 0);
std::cout << "is Not a Var\n";
} else {
// is an non-existant key
}
}
}
} else if (state == 1) {
@@ -740,7 +769,7 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
continue;
}
std::cout << "doExpression3 - calling [" << callFuncName << "](" << params << ") at [" << callFunc << "] with [" << callFunc->tokens.size() << "]tokens\n";
stack = doFunctionCall(callFunc, params, rootScope);
stack = jsFunctionCall(callFuncName, callFunc, params, rootScope);
state = 0;
} else {
std::cout << "doExpression3 - func call did not have (\n";
@@ -1830,6 +1859,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
expression_parts.push_back("=");
state = 2;
}
// FIXME: pull out all the expression parsing stuff
// ||
if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
@@ -2091,27 +2121,31 @@ bool doAssignment(js_function &rootScope, std::string token) {
bool negate = false;
js_function *func = nullptr;
js_function *callFunc = nullptr;
std::string callFuncName = "";
std::string prototype = "";
std::string params = "";
js_internal_storage *stack = nullptr;
for(auto it : expression_parts) {
// probably should trim these
std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment expression(" << doAssignmentLevel << ") token[" << it << "]" << std::to_string(state) << std::endl;
// default: put token in left, get op (usually =) and then get right side
std::string trimmedToken = trim(it);
if (state==0) {
negate = false;
prototype = "";
if (it == "=") {
if (trimmedToken == "=") {
left = lastToken;
state = 1;
}
if (it == "&&") {
if (trimmedToken == "&&") {
// if stack is false...
std::cout << "stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
//return true;
}
// can actually go to 9 (include the space)
std::string first8 = it.substr(0, 8);
std::string first8 = trimmedToken.substr(0, 8);
if (first8 == "function") {
left = it.substr(8);
left = trimmedToken.substr(8);
// well it can be "function()"
// no left and no starting brace...
cursor = locateFunctionParamsEnd(left, 0);
@@ -2126,28 +2160,47 @@ bool doAssignment(js_function &rootScope, std::string token) {
// (function() {}())
// token will matter here
// check for ()
if (it == "(") {
if (trimmedToken == "(") {
state = 8;
}
} else if (state == 1) {
if (it == "") continue; // skip empties, don't fire the assignment too early
if (trimmedToken == "") continue; // skip empties, don't fire the assignment too early
if (it == " ") continue; // skip empties, don't fire the assignment too early
if (it == "!") continue; // valid expression
if (it == "}") continue; // valid part of an expression (why are we getting this, should have a starting { and be in state 2)
if (trimmedToken == "!") continue; // valid expression
if (trimmedToken == "}") continue; // valid part of an expression (why are we getting this, should have a starting { and be in state 2)
// so these next 2 execute a function that's on the stack
// state 0: elem =
// state 1: funcName,(,proto,),;
if (it == "(") continue; // valid part of an expression
if (it == ")") continue; // valid part of an expression
if (it == "&&") continue; // valid part of an expression
if (it == "{") {
if (trimmedToken == "(") continue; // valid part of an expression
if (trimmedToken == ")") continue; // valid part of an expression
if (trimmedToken == "&&") {
// if stack is false...
std::cout << "state1 && stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
if (jsIsFalse(stack)) {
// skip the rest of the expression
// set variable to false
std::string tLeft = trim(left);
if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
//std::cout << "dequoting[" << tLeft << "]" << std::endl;
tLeft=tLeft.substr(1, tLeft.length() - 2);
}
rootScope.locals.value[tLeft] = stack;
assignfile << tLeft << "=" << it << "\n";
std::cout << "doAssignment &&false final assign[" << tLeft << "]=false\n";
return true;
}
} // valid part of an expression
if (trimmedToken == "{") {
state = 2;
} else {
js_internal_storage *storage = doExpression(rootScope, it);
js_internal_storage *storage = doExpression(rootScope, trimmedToken);
if (storage) {
// state 1 can be an expression that we need to push the result onto the stack for && ||
stack = storage;
js_function *funcTest = dynamic_cast<js_function*>(storage);
if (funcTest) {
callFuncName = trimmedToken;
callFunc = funcTest;
state = 9;
continue;
@@ -2168,7 +2221,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
}
}
if (!alreadySet) {
std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] scope[" << &rootScope << "]\n";
std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] storageFalse[" << jsIsFalse(storage) <<"] scope[" << &rootScope << "]\n";
rootScope.locals.value[tLeft] = storage;
jsDisplayScope(&rootScope, 0);
left = ""; // reset left
@@ -2264,19 +2317,19 @@ bool doAssignment(js_function &rootScope, std::string token) {
state = 5;
} else if (state == 4) {
if (it == "}") {
if (trimmedToken == "}") {
//displayScope(&rootScope, 0);
state = 5; // reset state
}
} else if (state == 5) { // function definition call check
// wait for ()
if (it == "(") {
if (trimmedToken == "(") {
state = 6;
} else {
state = 0; // reset
}
} else if (state == 6) { // call function just defined
if (it == ")") {
if (trimmedToken == ")") {
// parse/execute the tokens of said function
std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - calling just defined function, tokens[" << func->tokens.size() << "]\n";
if (func->tokens.size()) {
@@ -2289,7 +2342,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - WRITE ME collect params [" << it << "]\n";
}
} else if (state == 8) { // is a function call or expression
if (it == ")") {
if (trimmedToken == ")") {
state = 0; // reset state
} else {
// call params
@@ -2298,7 +2351,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
} else if (state == 9) { // are we a function call with return value, or assigning a function reference
js_internal_storage *storage = nullptr;
// we'll need a way to get tLeft back to set it
if (it == "(") {
if (trimmedToken == "(") {
// it's a function call
// set state = 10 until we get all prototype
state = 10;
@@ -2333,11 +2386,12 @@ bool doAssignment(js_function &rootScope, std::string token) {
}
}
} else if (state == 10) { // in function call params
if (it == ")") {
if (trimmedToken == ")") {
// use doFunctionCall
js_internal_storage *storage = nullptr;
std::cout << "calling function [" << callFunc << "](" << params << ")\n";
storage = doFunctionCall(callFunc, params, rootScope);
storage = jsFunctionCall(callFuncName, callFunc, params, rootScope);
//storage = doFunctionCall(callFunc, params, rootScope);
std::cout << "function retval[" << storage << "] type[" << typeOfStorage(storage) << "]\n";
if (storage) {
std::string tLeft = trim(left);
@@ -2366,7 +2420,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
state = 0;
} else {
// collect params
params = it;
params = trimmedToken;
}
}
// { starts JSON capture (should be exactly one block before the } token)
@@ -2465,6 +2519,7 @@ js_internal_storage **getObjectKeyPointer(const std::string input, const js_func
return &jobj->value[part2];
} else {
std::cout << "getObjectKeyPointer [" << baseObj << "] isnt an object\n";
// it's fine as long as the variable is defined
}
} else {
std::cout << "getObjectKeyPointer - Couldnt find base[" << baseObj << "] in scope" << std::endl;
@@ -2476,6 +2531,32 @@ js_internal_storage **getObjectKeyPointer(const std::string input, const js_func
return nullptr;
}

// we need the difference between base is there and not there
// dereferenceBaseExists
bool dereferenceHasBase(const std::string input, const js_function *scope) {
size_t dotPos = input.find('.');
if (dotPos != std::string::npos) {
std::string baseObj = input.substr(0, dotPos);
js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
if (baseStorage) {
return true;
}
}
dotPos = input.find('[');
if (dotPos != std::string::npos) {
size_t end = input.find(']');
if (end != std::string::npos) {
// we have an open and close
std::string baseObj = input.substr(0, dotPos);
js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
if (baseStorage) {
return true;
}
}
}
return false;
}

js_internal_storage *dereferenceObject(const std::string input, const js_function *scope) {
// FIXME: too simple, catches quoted strings with . in them
// FIXME: make sure we're not inside quotes
@@ -2498,6 +2579,7 @@ js_internal_storage *dereferenceObject(const std::string input, const js_functio
}
} else {
std::cout << "dereferenceObject - baseStorage couldn't be made a js_object. type[" << typeOfStorage(baseStorage) << "]\n";
// it's ok for a key to not exists in a defined variable
}
} else {
std::cout << "dereferenceObject - Couldnt find base[" << baseObj << "] in scope" << std::endl;
@@ -2573,7 +2655,7 @@ js_internal_storage *jsParseTokens(const std::vector<std::string> &tokens, js_fu
//end = ifStr.find(')');
std::string ifCondition = ifStr.substr(0, end);
js_internal_storage *expRes = doExpression(*scope, ifCondition);
bool conditionRes = jsIsFalse(expRes);
bool conditionRes = !jsIsFalse(expRes);
std::cout << "ifCondition[" << ifCondition << "] res[" << conditionRes << "]" << std::endl;
ifStr = ifStr.substr(0, end);
// then we'll use !isFalse to figure out if we need to exec this attached scope of code
@@ -2702,7 +2784,10 @@ js_internal_storage *jsParseTokens(const std::vector<std::string> &tokens, js_fu
execfile << "function call [" << funcName << "](" << arguments << ")\n";
js_internal_storage *storage = nullptr;
storage = dereferenceObject(funcName, scope);
bool deref = dereferenceHasBase(funcName, scope);
if (deref) {
storage = dereferenceObject(funcName, scope);
}
// need to convert to storage to create js_function object
if (storage == nullptr) {
storage = jsLocateKey(scope, funcName);

Loading…
Cancel
Save