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

Odilitime 7 months 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 @@
1 1
 #include "JSParser.h"
2
+#include "BrowserJS.h"
2 3
 #include "../../../tools/StringUtils.h"
3 4
 
4 5
 #include <iostream>
@@ -42,9 +43,11 @@ bool jsIsFalse(js_internal_storage *generic) {
42 43
         js_number *jnum = dynamic_cast<js_number*>(generic);
43 44
         return !jnum->value;
44 45
     } else
45
-    if (type == "bool") {
46
+        if (type == "bool") {
46 47
         js_bool *jb = dynamic_cast<js_bool*>(generic);
47 48
         return !jb->value;
49
+    } else if (type == "func") {
50
+        return false; // func are always true
48 51
     } else
49 52
     //if (type == "unknown") {
50 53
         // why is this needed?
@@ -280,12 +283,16 @@ std::vector<std::string> jsGetTokens(const std::string &source, const size_t sta
280 283
     return tokens;
281 284
 }
282 285
 
283
-js_internal_storage *doFunctionCall(js_function *func, std::string params, js_function &scope) {
284
-    if (func == nullptr) {
285
-        std::cout << "passed null into doFunctionCall\n";
286
-        return nullptr;
286
+js_internal_storage *jsFunctionCall(std::string funcName, js_function *func, std::string params, js_function &scope) {
287
+    if (isConstruct(funcName)) {
288
+        return executeConstruct(funcName, params, scope);
289
+    } else {
290
+        if (func == nullptr) {
291
+            std::cout << "passed null into jsFunctionCall\n";
292
+            return nullptr;
293
+        }
294
+        return jsParseTokens(func->tokens, &scope);
287 295
     }
288
-    return jsParseTokens(func->tokens, &scope);
289 296
 }
290 297
 
291 298
 // 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) {
361 368
             }
362 369
             // ||
363 370
             if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
364
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
371
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
365 372
                 expression_parts.push_back("||");
366 373
             }
367 374
             if (token[cursor] == '&' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
@@ -377,27 +384,27 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
377 384
                 expression_parts.push_back("<");
378 385
             }
379 386
             if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
380
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
387
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
381 388
                 expression_parts.push_back("<=");
382 389
             }
383 390
             if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
384
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
391
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
385 392
                 expression_parts.push_back(">=");
386 393
             }
387 394
             if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
388
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
395
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
389 396
                 expression_parts.push_back("==");
390 397
             }
391 398
             if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
392
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
399
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
393 400
                 expression_parts.push_back("===");
394 401
             }
395 402
             if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
396
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
403
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
397 404
                 expression_parts.push_back("!=");
398 405
             }
399 406
             if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
400
-                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
407
+                expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
401 408
                 expression_parts.push_back("!==");
402 409
             }
403 410
             // +
@@ -407,7 +414,7 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
407 414
             } else
408 415
             if (token[cursor] == '-') {
409 416
                 expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
410
-                expression_parts.push_back("+");
417
+                expression_parts.push_back("-");
411 418
             } else
412 419
             if (token[cursor] == '*') {
413 420
                 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) {
542 549
                 // if stack is false abort
543 550
                 std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
544 551
                 std::string type = typeOfStorage(stack);
552
+                if (jsIsFalse(stack)) {
553
+                    std::cout << "&& stack isFalse\n";
554
+                }
545 555
                 if (type=="string") {
546 556
                     js_string *string = dynamic_cast<js_string*>(stack);
547 557
                     std::cout << "stack points to [" << stack << "] value[" << string->value << "]\n";
@@ -573,6 +583,17 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
573 583
                 }
574 584
                 continue;
575 585
             }
586
+            // ||
587
+            if (trimmedToken == "||") {
588
+                std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
589
+                std::string type = typeOfStorage(stack);
590
+                if (jsIsFalse(stack)) {
591
+                    // stack is false, we have to execute next expression
592
+                    continue;
593
+                }
594
+                // if stack is true, we don't need to evaulate the rest
595
+                std::cout << "No need to execute the rest of this expression\n";
596
+            }
576 597
             if (trimmedToken == "!") {
577 598
                 state = 4;
578 599
                 continue;
@@ -622,20 +643,23 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
622 643
             // variable
623 644
             
624 645
             // object.property
625
-            js_internal_storage *dereferenceTest = dereferenceObject(trimmedToken, &rootScope);
626
-            if (dereferenceTest) {
627
-                if (typeOfStorage(dereferenceTest)=="func") {
628
-                    // it could be a call...
629
-                    callFuncName = it;
630
-                    callFunc = dynamic_cast<js_function *>(dereferenceTest);
631
-                    if (!callFunc) {
632
-                        std::cout << "Couldnt cast deference to func\n";
646
+            bool deref = dereferenceHasBase(trimmedToken, &rootScope);
647
+            if (deref) {
648
+                js_internal_storage *dereferenceTest = dereferenceObject(trimmedToken, &rootScope);
649
+                if (dereferenceTest) {
650
+                    if (typeOfStorage(dereferenceTest)=="func") {
651
+                        // it could be a call...
652
+                        callFuncName = it;
653
+                        callFunc = dynamic_cast<js_function *>(dereferenceTest);
654
+                        if (!callFunc) {
655
+                            std::cout << "Couldnt cast deference to func\n";
656
+                        }
657
+                        state = 1;
658
+                    } else {
659
+                        stack = dereferenceTest;
633 660
                     }
634
-                    state = 1;
635
-                } else {
636
-                    stack = dereferenceTest;
661
+                    continue;
637 662
                 }
638
-                continue;
639 663
             }
640 664
             
641 665
             // it's a string constant
@@ -688,8 +712,8 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
688 712
                 std::cout << "isVar [" << isVar << "]\n";
689 713
                 std::cout << "stack could be [" << *isVar << "] type[" << typeOfStorage(stack) << "]\n";
690 714
                 if (typeOfStorage(stack)=="func") {
691
-                    callFuncName = it;
692
-                    callFunc = dynamic_cast<js_function *>(dereferenceTest);
715
+                    callFuncName = trimmedToken;
716
+                    callFunc = dynamic_cast<js_function *>(stack);
693 717
                     state = 1;
694 718
                     // (
695 719
                     // 1
@@ -706,10 +730,15 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
706 730
             } else {
707 731
                 js_internal_storage *scopeTest = jsLocateKey(&rootScope, it);
708 732
                 if (scopeTest) {
733
+                    std::cout << "locatedKey stack[" << scopeTest << "] stackFalse[" << jsIsFalse(scopeTest) << "]\n";
709 734
                     stack = scopeTest;
710 735
                 } else {
711
-                    jsDisplayScope(&rootScope, 0);
712
-                    std::cout << "is Not a Var\n";
736
+                    if (!deref) {
737
+                        jsDisplayScope(&rootScope, 0);
738
+                        std::cout << "is Not a Var\n";
739
+                    } else {
740
+                        // is an non-existant key
741
+                    }
713 742
                 }
714 743
             }
715 744
         } else if (state == 1) {
@@ -740,7 +769,7 @@ js_internal_storage *doExpression(js_function &rootScope, std::string token) {
740 769
                     continue;
741 770
                 }
742 771
                 std::cout << "doExpression3 - calling [" << callFuncName << "](" << params << ") at [" << callFunc << "] with [" << callFunc->tokens.size() << "]tokens\n";
743
-                stack = doFunctionCall(callFunc, params, rootScope);
772
+                stack = jsFunctionCall(callFuncName, callFunc, params, rootScope);
744 773
                 state = 0;
745 774
             } else {
746 775
                 std::cout << "doExpression3 - func call did not have (\n";
@@ -1830,6 +1859,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
1830 1859
                 expression_parts.push_back("=");
1831 1860
                 state = 2;
1832 1861
             }
1862
+            // FIXME: pull out all the expression parsing stuff
1833 1863
             // ||
1834 1864
             if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
1835 1865
                 expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
@@ -2091,27 +2121,31 @@ bool doAssignment(js_function &rootScope, std::string token) {
2091 2121
     bool negate = false;
2092 2122
     js_function *func = nullptr;
2093 2123
     js_function *callFunc = nullptr;
2124
+    std::string callFuncName = "";
2094 2125
     std::string prototype = "";
2095 2126
     std::string params = "";
2127
+    js_internal_storage *stack = nullptr;
2096 2128
     for(auto it : expression_parts) {
2097 2129
         // probably should trim these
2098 2130
         std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment expression(" << doAssignmentLevel << ") token[" << it << "]" << std::to_string(state) << std::endl;
2099 2131
         // default: put token in left, get op (usually =) and then get right side
2132
+        std::string trimmedToken = trim(it);
2100 2133
         if (state==0) {
2101 2134
             negate = false;
2102 2135
             prototype = "";
2103
-            if (it == "=") {
2136
+            if (trimmedToken == "=") {
2104 2137
                 left = lastToken;
2105 2138
                 state = 1;
2106 2139
             }
2107
-            if (it == "&&") {
2140
+            if (trimmedToken == "&&") {
2108 2141
                 // if stack is false...
2142
+                std::cout << "stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
2109 2143
                 //return true;
2110 2144
             }
2111 2145
             // can actually go to 9 (include the space)
2112
-            std::string first8 = it.substr(0, 8);
2146
+            std::string first8 = trimmedToken.substr(0, 8);
2113 2147
             if (first8 == "function") {
2114
-                left = it.substr(8);
2148
+                left = trimmedToken.substr(8);
2115 2149
                 // well it can be "function()"
2116 2150
                 // no left and no starting brace...
2117 2151
                 cursor = locateFunctionParamsEnd(left, 0);
@@ -2126,28 +2160,47 @@ bool doAssignment(js_function &rootScope, std::string token) {
2126 2160
             // (function() {}())
2127 2161
             // token will matter here
2128 2162
             // check for ()
2129
-            if (it == "(") {
2163
+            if (trimmedToken == "(") {
2130 2164
                 state = 8;
2131 2165
             }
2132 2166
         } else if (state == 1) {
2133
-            if (it == "") continue; // skip empties, don't fire the assignment too early
2167
+            if (trimmedToken == "") continue; // skip empties, don't fire the assignment too early
2134 2168
             if (it == " ") continue; // skip empties, don't fire the assignment too early
2135
-            if (it == "!") continue; // valid expression
2136
-            if (it == "}") continue; // valid part of an expression (why are we getting this, should have a starting { and be in state 2)
2169
+            if (trimmedToken == "!") continue; // valid expression
2170
+            if (trimmedToken == "}") continue; // valid part of an expression (why are we getting this, should have a starting { and be in state 2)
2137 2171
             // so these next 2 execute a function that's on the stack
2138 2172
             // state 0: elem =
2139 2173
             // state 1: funcName,(,proto,),;
2140
-            if (it == "(") continue; // valid part of an expression
2141
-            if (it == ")") continue; // valid part of an expression
2142
-            if (it == "&&") continue; // valid part of an expression
2143
-            if (it == "{") {
2174
+            if (trimmedToken == "(") continue; // valid part of an expression
2175
+            if (trimmedToken == ")") continue; // valid part of an expression
2176
+            if (trimmedToken == "&&") {
2177
+                // if stack is false...
2178
+                std::cout << "state1 && stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
2179
+                if (jsIsFalse(stack)) {
2180
+                    // skip the rest of the expression
2181
+                    // set variable to false
2182
+                    std::string tLeft = trim(left);
2183
+                    if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
2184
+                        //std::cout << "dequoting[" << tLeft << "]" << std::endl;
2185
+                        tLeft=tLeft.substr(1, tLeft.length() - 2);
2186
+                    }
2187
+                    rootScope.locals.value[tLeft] = stack;
2188
+                    assignfile << tLeft << "=" << it << "\n";
2189
+                    std::cout << "doAssignment &&false final assign[" << tLeft << "]=false\n";
2190
+                    return true;
2191
+                }
2192
+            } // valid part of an expression
2193
+            if (trimmedToken == "{") {
2144 2194
                 state = 2;
2145 2195
             } else {
2146 2196
                 
2147
-                js_internal_storage *storage = doExpression(rootScope, it);
2197
+                js_internal_storage *storage = doExpression(rootScope, trimmedToken);
2148 2198
                 if (storage) {
2199
+                    // state 1 can be an expression that we need to push the result onto the stack for && ||
2200
+                    stack = storage;
2149 2201
                     js_function *funcTest = dynamic_cast<js_function*>(storage);
2150 2202
                     if (funcTest) {
2203
+                        callFuncName = trimmedToken;
2151 2204
                         callFunc = funcTest;
2152 2205
                         state = 9;
2153 2206
                         continue;
@@ -2168,7 +2221,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
2168 2221
                         }
2169 2222
                     }
2170 2223
                     if (!alreadySet) {
2171
-                        std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] scope[" << &rootScope << "]\n";
2224
+                        std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] storageFalse[" << jsIsFalse(storage) <<"] scope[" << &rootScope << "]\n";
2172 2225
                         rootScope.locals.value[tLeft] = storage;
2173 2226
                         jsDisplayScope(&rootScope, 0);
2174 2227
                         left = ""; // reset left
@@ -2264,19 +2317,19 @@ bool doAssignment(js_function &rootScope, std::string token) {
2264 2317
             
2265 2318
             state = 5;
2266 2319
         } else if (state == 4) {
2267
-            if (it == "}") {
2320
+            if (trimmedToken == "}") {
2268 2321
                 //displayScope(&rootScope, 0);
2269 2322
                 state = 5; // reset state
2270 2323
             }
2271 2324
         } else if (state == 5) { // function definition call check
2272 2325
             // wait for ()
2273
-            if (it == "(") {
2326
+            if (trimmedToken == "(") {
2274 2327
                 state = 6;
2275 2328
             } else {
2276 2329
                 state = 0; // reset
2277 2330
             }
2278 2331
         } else if (state == 6) { // call function just defined
2279
-            if (it == ")") {
2332
+            if (trimmedToken == ")") {
2280 2333
                 // parse/execute the tokens of said function
2281 2334
                 std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - calling just defined function, tokens[" << func->tokens.size() << "]\n";
2282 2335
                 if (func->tokens.size()) {
@@ -2289,7 +2342,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
2289 2342
                 std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - WRITE ME collect params [" << it << "]\n";
2290 2343
             }
2291 2344
         } else if (state == 8) { // is a function call or expression
2292
-            if (it == ")") {
2345
+            if (trimmedToken == ")") {
2293 2346
                 state = 0; // reset state
2294 2347
             } else {
2295 2348
                 // call params
@@ -2298,7 +2351,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
2298 2351
         } else if (state == 9) { // are we a function call with return value, or assigning a function reference
2299 2352
             js_internal_storage *storage = nullptr;
2300 2353
             // we'll need a way to get tLeft back to set it
2301
-            if (it == "(") {
2354
+            if (trimmedToken == "(") {
2302 2355
                 // it's a function call
2303 2356
                 // set state = 10 until we get all prototype
2304 2357
                 state = 10;
@@ -2333,11 +2386,12 @@ bool doAssignment(js_function &rootScope, std::string token) {
2333 2386
                 }
2334 2387
             }
2335 2388
         } else if (state == 10) { // in function call params
2336
-            if (it == ")") {
2389
+            if (trimmedToken == ")") {
2337 2390
                // use doFunctionCall
2338 2391
                 js_internal_storage *storage = nullptr;
2339 2392
                 std::cout << "calling function [" << callFunc << "](" << params << ")\n";
2340
-                storage = doFunctionCall(callFunc, params, rootScope);
2393
+                storage = jsFunctionCall(callFuncName, callFunc, params, rootScope);
2394
+                //storage = doFunctionCall(callFunc, params, rootScope);
2341 2395
                 std::cout << "function retval[" << storage << "] type[" << typeOfStorage(storage) << "]\n";
2342 2396
                 if (storage) {
2343 2397
                     std::string tLeft = trim(left);
@@ -2366,7 +2420,7 @@ bool doAssignment(js_function &rootScope, std::string token) {
2366 2420
                 state = 0;
2367 2421
             } else {
2368 2422
                 // collect params
2369
-                params = it;
2423
+                params = trimmedToken;
2370 2424
             }
2371 2425
         }
2372 2426
         // { 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
2465 2519
                 return &jobj->value[part2];
2466 2520
             } else {
2467 2521
                 std::cout << "getObjectKeyPointer [" << baseObj << "] isnt an object\n";
2522
+                // it's fine as long as the variable is defined
2468 2523
             }
2469 2524
         } else {
2470 2525
             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
2476 2531
     return nullptr;
2477 2532
 }
2478 2533
 
2534
+// we need the difference between base is there and not there
2535
+// dereferenceBaseExists
2536
+bool dereferenceHasBase(const std::string input, const js_function *scope) {
2537
+    size_t dotPos = input.find('.');
2538
+    if (dotPos != std::string::npos) {
2539
+        std::string baseObj = input.substr(0, dotPos);
2540
+        js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
2541
+        if (baseStorage) {
2542
+            return true;
2543
+        }
2544
+    }
2545
+    dotPos = input.find('[');
2546
+    if (dotPos != std::string::npos) {
2547
+        size_t end = input.find(']');
2548
+        if (end != std::string::npos) {
2549
+            // we have an open and close
2550
+            std::string baseObj = input.substr(0, dotPos);
2551
+            js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
2552
+            if (baseStorage) {
2553
+                return true;
2554
+            }
2555
+        }
2556
+    }
2557
+    return false;
2558
+}
2559
+
2479 2560
 js_internal_storage *dereferenceObject(const std::string input, const js_function *scope) {
2480 2561
     // FIXME: too simple, catches quoted strings with . in them
2481 2562
     // FIXME: make sure we're not inside quotes
@@ -2498,6 +2579,7 @@ js_internal_storage *dereferenceObject(const std::string input, const js_functio
2498 2579
                 }
2499 2580
             } else {
2500 2581
                 std::cout << "dereferenceObject - baseStorage couldn't be made a js_object. type[" << typeOfStorage(baseStorage) << "]\n";
2582
+                // it's ok for a key to not exists in a defined variable
2501 2583
             }
2502 2584
         } else {
2503 2585
             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
2573 2655
             //end = ifStr.find(')');
2574 2656
             std::string ifCondition = ifStr.substr(0, end);
2575 2657
             js_internal_storage *expRes = doExpression(*scope, ifCondition);
2576
-            bool conditionRes = jsIsFalse(expRes);
2658
+            bool conditionRes = !jsIsFalse(expRes);
2577 2659
             std::cout << "ifCondition[" << ifCondition << "] res[" << conditionRes << "]" << std::endl;
2578 2660
             ifStr = ifStr.substr(0, end);
2579 2661
             // 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
2702 2784
                 execfile << "function call [" << funcName << "](" << arguments << ")\n";
2703 2785
                 
2704 2786
                 js_internal_storage *storage = nullptr;
2705
-                storage = dereferenceObject(funcName, scope);
2787
+                bool deref = dereferenceHasBase(funcName, scope);
2788
+                if (deref) {
2789
+                    storage = dereferenceObject(funcName, scope);
2790
+                }
2706 2791
                 // need to convert to storage to create js_function object
2707 2792
                 if (storage == nullptr) {
2708 2793
                     storage = jsLocateKey(scope, funcName);