You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JSParser.cpp 134KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945
  1. #include "JSParser.h"
  2. #include "BrowserJS.h"
  3. #include "../../../tools/StringUtils.h"
  4. #include <iostream>
  5. #include <fstream>
  6. #include <algorithm>
  7. extern std::ofstream assignfile;
  8. extern std::ofstream execfile;
  9. std::string typeOfStorage(js_internal_storage *storage) {
  10. if (!storage) {
  11. std::cout << "null passed into typeOfStorage\n";
  12. return "Corrupt";
  13. }
  14. js_string *string = dynamic_cast<js_string*>(storage);
  15. if (string) return "string";
  16. js_number *number = dynamic_cast<js_number*>(storage);
  17. if (number) return "number";
  18. js_bool *jbool = dynamic_cast<js_bool*>(storage);
  19. if (jbool) return "bool";
  20. js_function *func = dynamic_cast<js_function*>(storage);
  21. if (func) return "func";
  22. js_array *arr = dynamic_cast<js_array*>(storage);
  23. if (arr) return "array";
  24. js_object *obj = dynamic_cast<js_object*>(storage);
  25. if (obj) return "object";
  26. js_reference *ref = dynamic_cast<js_reference*>(storage);
  27. if (ref) return "reference";
  28. js_forward *fwd = dynamic_cast<js_forward*>(storage);
  29. if (fwd) return "forward";
  30. return "unknown";
  31. }
  32. bool jsIsFalse(js_internal_storage *generic) {
  33. std::string type = typeOfStorage(generic);
  34. if (type == "string") {
  35. js_string *string = dynamic_cast<js_string*>(generic);
  36. return string->value == "" || string->value == "0";
  37. } else
  38. if (type == "number") {
  39. js_number *jnum = dynamic_cast<js_number*>(generic);
  40. return !jnum->value;
  41. } else
  42. if (type == "bool") {
  43. js_bool *jb = dynamic_cast<js_bool*>(generic);
  44. return !jb->value;
  45. } else if (type == "func") {
  46. return false; // func are always true
  47. } else
  48. //if (type == "unknown") {
  49. // why is this needed?
  50. //return true;
  51. //} else
  52. if (type == "Corrupt") {
  53. return true;
  54. } else {
  55. std::cout << "unknown type [" << type << "]\n";
  56. }
  57. return false;
  58. }
  59. js_internal_storage *jsLocateKey(const js_function *scope, const std::string key) {
  60. // do we have it?
  61. auto locate = scope->locals.value.find(key);
  62. if (locate == scope->locals.value.end()) {
  63. // we do have a parent?
  64. if (scope->parentScope) {
  65. return jsLocateKey(scope->parentScope, key);
  66. }
  67. // no parent
  68. return nullptr;
  69. }
  70. // we have it
  71. return locate->second;
  72. }
  73. std::string jsLocatePtrKey(const js_function *scope, js_internal_storage *val) {
  74. // do we have it?
  75. std::string sourceKey = "";
  76. for(auto it2 : scope->locals.value) {
  77. std::cout << "ptr[" << val << "]==[" << it2.second << "] root[" << scope << "]\n";
  78. if (it2.second == val) {
  79. return it2.first;
  80. break;
  81. }
  82. }
  83. // we do have a parent?
  84. if (scope->parentScope) {
  85. return jsLocatePtrKey(scope->parentScope, val);
  86. }
  87. // no parent
  88. return "";
  89. }
  90. void jsDisplayScope(const js_function *scope, size_t level) {
  91. std::cout << "There are " << scope->locals.value.size() << " elements at this level " << level << "\n";
  92. for(auto it : scope->locals.value) {
  93. std::string type = typeOfStorage(it.second);
  94. if (type == "string") {
  95. js_string *string = dynamic_cast<js_string*>(it.second);
  96. std::cout << "[" << level << "]" << "[" << it.first << "] stringValue[" << string->value << "] address[" << it.second << "]\n";
  97. } else {
  98. std::cout << "[" << level << "]" << "[" << it.first << "] type[" << type << "] address[" << it.second << "]\n";
  99. }
  100. }
  101. if (scope->parentScope) {
  102. level++;
  103. jsDisplayScope(scope->parentScope, level);
  104. }
  105. }
  106. // if a function don't pass a starting or ending {}
  107. std::vector<std::string> jsGetTokens(const std::string &source, const size_t start) {
  108. std::vector<std::string> tokens;
  109. //std::cout << "jsGetTokens start [" << source.substr(start) << "]\n";
  110. // tokenize it
  111. size_t cursor;
  112. unsigned char state = 0;
  113. size_t last = start?start - 1 : 0;
  114. size_t quoteStart = 0;
  115. size_t scopeLevel = 0;
  116. size_t jsonStart = 0;
  117. size_t jsonLevel = 0;
  118. size_t parenLevel = 0;
  119. size_t parenStart = 0;
  120. size_t functionStart = 0;
  121. for (cursor = start; cursor < source.length(); cursor++) {
  122. //std::cout << "jsGetTokens step [" << cursor << "] char[" << source[cursor] << "] state[" << std::to_string(state) << "] scopeLevel[" << scopeLevel << "]\n";
  123. if (state == 0) {
  124. if (source[cursor] == '{') {
  125. state = 1; // JSON
  126. jsonStart = cursor;
  127. jsonLevel++;
  128. //std::cout << "Entering JSON: " << cursor << std::endl;
  129. } else if (source[cursor] == '(') {
  130. state = 8; // in a function call or prototype
  131. parenStart = cursor;
  132. parenLevel++;
  133. } else if (source[cursor] == '\'') { // quotes just for allowing [;{}\n] in quotes
  134. quoteStart = cursor;
  135. state = 4;
  136. } else if (source[cursor] == '"') {
  137. quoteStart = cursor;
  138. state = 5;
  139. } else if (source[cursor] == '/' && source.length() > cursor + 1 && source[cursor + 1] == '/') {
  140. // single line comment
  141. state = 2;
  142. } else if (source[cursor] == '/' && source.length() > cursor + 1 && source[cursor + 1] == '*') {
  143. // Multiline comment
  144. state = 3;
  145. } else if (source[cursor] == '/') {
  146. // regex
  147. if (source.length() > cursor + 1) {
  148. size_t endex = locateRegexEnd(source, cursor + 1); // +1 because it can't start on /
  149. cursor = endex; // put here after regex
  150. // state = 9;
  151. } else {
  152. std::cout << "jsGetTokens - warning - no characters left in state 0\n";
  153. }
  154. } else if (source[cursor] == 'v' && source.length() > cursor + 3 && source[cursor + 1] == 'a'
  155. && source[cursor + 2] == 'r' && source[cursor + 3] == ' ') {
  156. // var
  157. state = 7;
  158. } else if (source[cursor] == 'f' && source.length() > cursor + 8 && source[cursor + 1] == 'u'
  159. && source[cursor + 2] == 'n' && source[cursor + 3] == 'c' && source[cursor + 4] == 't'
  160. && source[cursor + 5] == 'i' && source[cursor + 6] == 'o' && source[cursor + 7] == 'n') {
  161. //std::cout << "Entering function: " << cursor << std::endl;
  162. state = 6;
  163. functionStart = cursor;
  164. } else if (source[cursor] == 'r' && source.length() > cursor + 5 && source[cursor + 1] == 'e'
  165. && source[cursor + 2] == 't' && source[cursor + 3] == 'u' && source[cursor + 4] == 'r'
  166. && source[cursor + 5] == 'n') {
  167. // return state, have to ignore , until ; or new line
  168. state = 9;
  169. }
  170. } else if (state == 1) {
  171. // inside a scope (JSON)
  172. if (source[cursor] == '{') {
  173. jsonLevel++;
  174. } else if (source[cursor] == '}') {
  175. jsonLevel--;
  176. if (!jsonLevel) {
  177. //std::cout << "Exiting JSON: " << source.substr(jsonStart, cursor - jsonStart) << "\n" << std::endl;
  178. state = 0; // exit JSON
  179. }
  180. }
  181. } else if (state == 8) {
  182. // inside a paren (function)
  183. //std::cout << "looking at [" << source[cursor] << "]@" << cursor << std::endl;
  184. if (source[cursor] == '(') {
  185. parenLevel++;
  186. } else if (source[cursor] == ')') {
  187. parenLevel--;
  188. if (!parenLevel) {
  189. //std::cout << "Exiting Paren: " << source.substr(parenStart, cursor - parenStart) << "\n" << std::endl;
  190. state = 0; // exit JSON
  191. }
  192. }
  193. } else if (state == 2) {
  194. // inside a single line comment
  195. if (source[cursor] == '\n') {
  196. last = cursor;
  197. state = 0;
  198. }
  199. } else if (state == 3) {
  200. // inside a multiline comment
  201. if (source[cursor] == '*' && source.length() > cursor + 1 && source[cursor + 1] == '/') {
  202. // end multiline comment
  203. last = cursor;
  204. state = 0;
  205. }
  206. } else if (state == 4) {
  207. // inside single quote
  208. if (source[cursor] == '\'') {
  209. if (source[cursor - 1] != '\\') {
  210. //std::string quote = source.substr(quoteStart + 1, cursor - quoteStart - 1);
  211. //std::cout << "single quote: " << quote << std::endl;
  212. state = 0;
  213. }
  214. }
  215. } else if (state == 5) {
  216. // inside double quote
  217. if (source[cursor] == '"') {
  218. if (source[cursor - 1] != '\\') {
  219. //std::string quote = source.substr(quoteStart + 1, cursor - quoteStart - 1);
  220. //std::cout << "double quote: " << quote << std::endl;
  221. state = 0;
  222. }
  223. }
  224. } else if (state == 7) {
  225. }
  226. //
  227. if (source[cursor] == '{') {
  228. scopeLevel++;
  229. }
  230. bool endIt = false;
  231. if (source[cursor] == '}') {
  232. scopeLevel--;
  233. if (state == 6 && !scopeLevel) {
  234. //std::cout << "Exiting function: " << source.substr(functionStart, cursor - functionStart) << "\n" << std::endl;
  235. state = 0;
  236. endIt = true;
  237. }
  238. }
  239. // state 0 or 7, ignore states 1-6
  240. if ((state == 0 || state == 7 || state == 9) && !scopeLevel) {
  241. // , if state (not 7) or (not 9)
  242. if (source[cursor] == '\n' || source[cursor] == ';' || endIt || (source[cursor] == ',' && state == 0)) {
  243. // FIXME: ; in for loops
  244. std::string token = source.substr(last ? last + 1 : last, last ? (cursor - last - 1) : cursor );
  245. if (source[cursor] == '}') {
  246. token += '}';
  247. }
  248. // scopeLevel[" << scopeLevel << "]"
  249. std::cout << "got token [" << token << "] ending[" << source[cursor] << "] endIt[" << endIt << "]" << std::endl;
  250. if (token.length()<3) {
  251. //std::cout << "token too short [" << token << "]" << std::endl;
  252. } else {
  253. tokens.push_back(token);
  254. }
  255. last = cursor;
  256. // state 7 or 9
  257. if (state != 0) { // allow var constructs to end normally and take us out of var construct
  258. state = 0; // reset state
  259. }
  260. }
  261. }
  262. }
  263. std::string token = source.substr(last ? last + 1 : last, last ? (cursor - last - 1) : cursor );
  264. //&& !token.length() // all look like complete valid tokens
  265. // state 9 (return), perfect ok to run to the end
  266. if (!state || state == 9) {
  267. if (token.length()) {
  268. // we can't just be discarding stuff
  269. tokens.push_back(token);
  270. }
  271. return tokens;
  272. }
  273. std::cout << "jsGetTokens - out of characters in state " << std::to_string(state) << " token[" << token << "]" << std::endl;
  274. std::cout << "got token [" << token << "] ending[" << source[cursor] << "]" << std::endl;
  275. if (token.length()<3) {
  276. std::cout << "token too short [" << token << "]" << std::endl;
  277. } else {
  278. tokens.push_back(token);
  279. }
  280. return tokens;
  281. }
  282. js_internal_storage *jsFunctionCall(std::string funcName, js_function *func, std::string params, js_function &scope) {
  283. if (isConstruct(funcName)) {
  284. return executeConstruct(funcName, params, scope);
  285. } else {
  286. if (func == nullptr) {
  287. std::cout << "passed null into jsFunctionCall\n";
  288. return nullptr;
  289. }
  290. return jsParseTokens(func->tokens, &scope);
  291. }
  292. }
  293. // this should evaluate an expression and return it's return value
  294. int doExpressionLevel = 0;
  295. js_internal_storage *doExpression(js_function &rootScope, std::string token) {
  296. std::vector<std::string> expression_parts;
  297. size_t cursor;
  298. size_t last = 0;
  299. size_t quoteStart = 0;
  300. size_t parenStart = 0;
  301. size_t parenLevel = 0;
  302. size_t trinaryLevel = 0;
  303. unsigned char state = 0;
  304. std::cout << "doExpression start[" << token << "]\n";
  305. // parse expression
  306. for (cursor = 0; cursor < token.length(); cursor++) {
  307. std::cout << "doExpression parse phase state[" << std::to_string(state) << "] char[" << token[cursor] << "]\n";
  308. if (state == 0) {
  309. // ||
  310. // &&
  311. // <, >, <=, >=, ==, ===, !=, !==
  312. // +, -
  313. // *, /, %, !
  314. // ?, >>, <<
  315. if (token[cursor] == 'f' && token.length() > cursor + 7 && token[cursor + 1] == 'u'
  316. && token[cursor + 2] == 'n' && token[cursor + 3] == 'c' && token[cursor + 4] == 't'
  317. && token[cursor + 5] == 'i' && token[cursor + 6] == 'o' && token[cursor + 7] == 'n') {
  318. state = 3;
  319. }
  320. if (token[cursor] == '\'') {
  321. quoteStart = cursor;
  322. state = 4;
  323. } else
  324. if (token[cursor] == '"') {
  325. quoteStart = cursor;
  326. state = 5;
  327. } else
  328. if (token[cursor] == '(') {
  329. parenStart = cursor;
  330. parenLevel++;
  331. state = 8;
  332. if (last != cursor) {
  333. // could be a func call or func def (w/ or w/o call)
  334. expression_parts.push_back(token.substr(last, cursor - last));
  335. }
  336. last = cursor + 1;
  337. expression_parts.push_back("(");
  338. } else
  339. if (token[cursor] == '{') {
  340. parenStart = cursor;
  341. parenLevel++;
  342. state = 1;
  343. //std::cout << "last " << last << " cursor " << cursor << std::endl;
  344. if (last != cursor) {
  345. expression_parts.push_back(token.substr(last, cursor - last - 1));
  346. }
  347. last = cursor + 1;
  348. expression_parts.push_back("{");
  349. }
  350. // single =
  351. if (token[cursor] == '=' && token.length() > cursor + 1 && token[cursor + 1] != '=') {
  352. //state = 1;
  353. //std::cout << "starting = at " << cursor << " last: " << last << std::endl;
  354. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  355. expression_parts.push_back("=");
  356. }
  357. // hack for JSON parsing
  358. if (token[cursor] == ':') {
  359. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  360. expression_parts.push_back("=");
  361. state = 2;
  362. }
  363. // ||
  364. if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
  365. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  366. expression_parts.push_back("||");
  367. }
  368. if (token[cursor] == '&' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
  369. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  370. expression_parts.push_back("&&");
  371. }
  372. if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] != '=' && token[cursor + 1] != '>') {
  373. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  374. expression_parts.push_back(">");
  375. }
  376. if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] != '=' && token[cursor + 1] != '<') {
  377. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  378. expression_parts.push_back("<");
  379. }
  380. if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
  381. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  382. expression_parts.push_back("<=");
  383. }
  384. if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
  385. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  386. expression_parts.push_back(">=");
  387. }
  388. if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
  389. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  390. expression_parts.push_back("==");
  391. }
  392. if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
  393. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
  394. expression_parts.push_back("===");
  395. }
  396. if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
  397. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  398. expression_parts.push_back("!=");
  399. }
  400. if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
  401. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
  402. expression_parts.push_back("!==");
  403. }
  404. // +
  405. if (token[cursor] == '+') {
  406. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  407. expression_parts.push_back("+");
  408. } else
  409. if (token[cursor] == '-') {
  410. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  411. expression_parts.push_back("-");
  412. } else
  413. if (token[cursor] == '*') {
  414. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  415. expression_parts.push_back("*");
  416. } else
  417. if (token[cursor] == '/') {
  418. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  419. expression_parts.push_back("/");
  420. } else
  421. if (token[cursor] == '%') {
  422. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  423. expression_parts.push_back("%");
  424. } else
  425. if (token[cursor] == '!') {
  426. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  427. expression_parts.push_back("!");
  428. } else
  429. if (token[cursor] == '?') {
  430. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  431. expression_parts.push_back("?");
  432. trinaryLevel++;
  433. state = 9;
  434. }
  435. } else if (state == 1) {
  436. if (token[cursor] == '{') {
  437. parenLevel++;
  438. } else
  439. if (token[cursor] == '}') {
  440. parenLevel--;
  441. if (!parenLevel) {
  442. expression_parts.push_back(token.substr(last, cursor - last));
  443. last = cursor + 1;
  444. expression_parts.push_back("}");
  445. state = 0;
  446. }
  447. }
  448. } else if (state == 2) { // json state (can be moved)
  449. if (token[cursor] == ',') {
  450. expression_parts.push_back(token.substr(last, cursor - last));
  451. last = cursor + 1;
  452. state = 0;
  453. }
  454. } else if (state == 3) { // function start (can be moved)
  455. if (token[cursor] == '{') {
  456. // lets put the function prototype
  457. expression_parts.push_back(token.substr(last, cursor - last));
  458. last = cursor + 1;
  459. parenLevel++;
  460. state = 6; // move to the function body
  461. }
  462. } else if (state == 4) {
  463. if (token[cursor] == '\'') {
  464. if (token[cursor - 1] != '\\') {
  465. //std::string quote = token.substr(quoteStart + 1, cursor - quoteStart - 1);
  466. //expression_parts.push_back(quote);
  467. //std::cout << "single quote: " << quote << std::endl;
  468. state = 0;
  469. }
  470. }
  471. } else if (state == 5) {
  472. if (token[cursor] == '"') {
  473. if (token[cursor - 1] != '\\') {
  474. //std::string quote = token.substr(quoteStart + 1, cursor - quoteStart - 1);
  475. //expression_parts.push_back(quote);
  476. //std::cout << "double quote: " << quote << std::endl;
  477. state = 0;
  478. }
  479. }
  480. } else if (state == 6) {
  481. if (token[cursor] == '{') {
  482. parenLevel++;
  483. } else
  484. if (token[cursor] == '}') {
  485. parenLevel--;
  486. if (!parenLevel) {
  487. expression_parts.push_back(token.substr(last, cursor - last));
  488. last = cursor + 1;
  489. expression_parts.push_back("}"); // end function
  490. state = 0;
  491. }
  492. }
  493. } else if (state == 8) {
  494. if (token[cursor] == '(') {
  495. parenLevel++;
  496. } else
  497. if (token[cursor] == ')') {
  498. parenLevel--;
  499. if (!parenLevel) {
  500. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  501. expression_parts.push_back(")");
  502. state = 0;
  503. }
  504. }
  505. } else if (state == 9) {
  506. if (token[cursor] == '?') {
  507. trinaryLevel++;
  508. } else
  509. if (token[cursor] == ':') {
  510. trinaryLevel--;
  511. if (!trinaryLevel) {
  512. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  513. expression_parts.push_back(":");
  514. state = 0;
  515. }
  516. }
  517. }
  518. }
  519. // flush last part
  520. std::cout << "doExpression end state[" << std::to_string(state) << "] cursor[" << cursor << "] last[" << last << "]\n";
  521. if (cursor != last) {
  522. std::cout << "pushing last part\n";
  523. expression_parts.push_back(token.substr(last, cursor - last));
  524. }
  525. // execute expression
  526. std::cout << "doExpression has [" << expression_parts.size() << "]parts\n";
  527. js_internal_storage *stack = nullptr;
  528. state = 0;
  529. std::string callFuncName = "";
  530. js_function *callFunc = nullptr;
  531. std::string params = "";
  532. //js_function *func = nullptr;
  533. size_t i = 0;
  534. for(auto it : expression_parts) {
  535. std::string trimmedToken = trim(it);
  536. i++;
  537. if (trimmedToken == "") continue;
  538. std::cout << "doExpression part[" << (i - 1) << "][" << it << "] state[" << std::to_string(state) << "]\n";
  539. if (state == 0) {
  540. // &&
  541. if (trimmedToken == "&&") {
  542. // if stack is false abort
  543. std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
  544. std::string type = typeOfStorage(stack);
  545. if (jsIsFalse(stack)) {
  546. std::cout << "&& stack isFalse\n";
  547. }
  548. if (type=="string") {
  549. js_string *string = dynamic_cast<js_string*>(stack);
  550. std::cout << "stack points to [" << stack << "] value[" << string->value << "]\n";
  551. if (string!=nullptr) {
  552. if (string->value == "" || string->value == "0") {
  553. std::cout << "I believe this value to be false [" << string->value << "]\n";
  554. return nullptr;
  555. } else {
  556. std::cout << "I believe this value to be not false [" << string->value << "]\n";
  557. }
  558. } else {
  559. std::cout << "couldnt convert string\n";
  560. }
  561. } else if (type == "number") {
  562. js_number *jnum = dynamic_cast<js_number*>(stack);
  563. std::cout << "stack points to [" << stack << "] value[" << jnum->value << "]\n";
  564. if (jnum!=nullptr) {
  565. if (!jnum->value) {
  566. std::cout << "I believe this value to be false [" << jnum->value << "]\n";
  567. return nullptr;
  568. } else {
  569. std::cout << "I believe this value to be not false [" << jnum->value << "]\n";
  570. }
  571. } else {
  572. std::cout << "couldnt convert string\n";
  573. }
  574. } else {
  575. std::cout << "doExpression, I don't know how to process this type - WRITE ME\n";
  576. }
  577. continue;
  578. }
  579. // ||
  580. if (trimmedToken == "||") {
  581. std::cout << "typeOf stack is [" << typeOfStorage(stack) << "]\n";
  582. std::string type = typeOfStorage(stack);
  583. if (jsIsFalse(stack)) {
  584. // stack is false, we have to execute next expression
  585. continue;
  586. }
  587. // if stack is true, we don't need to evaulate the rest
  588. std::cout << "No need to execute the rest of this expression\n";
  589. }
  590. if (trimmedToken == "!") {
  591. state = 4;
  592. continue;
  593. }
  594. if (trimmedToken == "{") {
  595. // parseJSON
  596. state = 5;
  597. continue;
  598. }
  599. std::string first8 = trimmedToken.substr(0, 8);
  600. if (first8 == "function") {
  601. std::string prototype = trimmedToken.substr(9, trimmedToken.length() - 10);
  602. std::cout << "extracted[" << prototype << "]\n";
  603. js_function *jsfunc = new js_function;
  604. jsfunc->parameters = split(prototype, ',');
  605. stack = jsfunc;
  606. continue;
  607. }
  608. // function name
  609. // (
  610. if (trimmedToken == "(") {
  611. // function call
  612. std::cout << "func call param start\n";
  613. state = 2;
  614. continue;
  615. }
  616. // function params
  617. // )
  618. if (trimmedToken == ")") {
  619. std::cout << "func call param end\n";
  620. state = 3;
  621. continue;
  622. }
  623. if (trimmedToken == "}") {
  624. // {return document.getElementById(e)}
  625. /*
  626. doExpression has [3]parts
  627. doExpression part[{] state[0]
  628. doExpression part[return document.getElementById(e)] state[5]
  629. */
  630. // ?
  631. continue;
  632. }
  633. // variable
  634. // object.property
  635. bool deref = dereferenceHasBase(trimmedToken, &rootScope);
  636. if (deref) {
  637. js_internal_storage *dereferenceTest = dereferenceObject(trimmedToken, &rootScope);
  638. if (dereferenceTest) {
  639. if (typeOfStorage(dereferenceTest)=="func") {
  640. // it could be a call...
  641. callFuncName = it;
  642. callFunc = dynamic_cast<js_function *>(dereferenceTest);
  643. if (!callFunc) {
  644. std::cout << "Couldnt cast deference to func\n";
  645. }
  646. state = 1;
  647. } else {
  648. stack = dereferenceTest;
  649. }
  650. continue;
  651. }
  652. }
  653. // it's a string constant
  654. if ((trimmedToken[0] == '"' && trimmedToken[trimmedToken.length() - 1] == '"') ||
  655. (trimmedToken[0] == '\'' && trimmedToken[trimmedToken.length() - 1] == '\'')) {
  656. js_string *jstring = new js_string;
  657. jstring->value = trimmedToken.substr(1, -1);
  658. stack = jstring;
  659. continue;
  660. }
  661. if (trimmedToken == "true") {
  662. js_bool *jbool = new js_bool;
  663. jbool->value = true;
  664. stack = jbool;
  665. continue;
  666. } else if (trimmedToken == "null") {
  667. // FIXME: is null a type?
  668. js_bool *jbool = new js_bool;
  669. jbool->value = false;
  670. stack = jbool;
  671. continue;
  672. } else if (trimmedToken == "false") {
  673. js_bool *jbool = new js_bool;
  674. jbool->value = false;
  675. stack = jbool;
  676. continue;
  677. }
  678. // number constant
  679. bool allDigits = true;
  680. for(auto it2 : trimmedToken) {
  681. if (it2 >= '0' && it2 <= '9') {
  682. } else {
  683. if (it2 != '.') {
  684. allDigits = false;
  685. }
  686. }
  687. }
  688. if (allDigits) {
  689. js_number *jnum = new js_number;
  690. jnum->value = std::stoi(trimmedToken);
  691. std::cout << "allDigits value[" << trimmedToken << "] => jnum[" << jnum->value << "]\n";
  692. stack = jnum;
  693. continue;
  694. }
  695. js_internal_storage **isVar = getObjectKeyPointer(it, &rootScope);
  696. if (isVar != nullptr) {
  697. std::cout << "isVar [" << isVar << "]\n";
  698. std::cout << "stack could be [" << *isVar << "] type[" << typeOfStorage(stack) << "]\n";
  699. if (typeOfStorage(stack)=="func") {
  700. callFuncName = trimmedToken;
  701. callFunc = dynamic_cast<js_function *>(stack);
  702. state = 1;
  703. // (
  704. // 1
  705. // )
  706. } else {
  707. stack = *isVar; // set stack to point to this variable
  708. }
  709. /*
  710. if (typeOfStorage(stack)=="string") {
  711. js_string *string = dynamic_cast<js_string*>(stack);
  712. std::cout << "string stack value[" << string->value << "]\n";
  713. }
  714. */
  715. } else {
  716. js_internal_storage *scopeTest = jsLocateKey(&rootScope, it);
  717. if (scopeTest) {
  718. std::cout << "locatedKey stack[" << scopeTest << "] stackFalse[" << jsIsFalse(scopeTest) << "]\n";
  719. stack = scopeTest;
  720. } else {
  721. if (!deref) {
  722. // well if it's prefixed with var, then we're creating var
  723. size_t hasVarPos = trimmedToken.find("var ");
  724. if (hasVarPos != std::string::npos) {
  725. std::string remainingExpr = trimmedToken.substr(hasVarPos + 4);
  726. std::cout << "variable name [" << remainingExpr << "] it[" << it << "]" << std::endl;
  727. // we're just initialling a blank variable
  728. js_internal_storage **storage = getObjectKeyPointer(remainingExpr, &rootScope);
  729. if (storage != nullptr) {
  730. // actually already exists, so stomp it
  731. *storage = new js_internal_storage; // FIXME;
  732. } else {
  733. // new variable
  734. rootScope.locals.value[remainingExpr] = new js_internal_storage;
  735. }
  736. stack = rootScope.locals.value[remainingExpr];
  737. /*
  738. rootScope.locals.value[remainingExpr] = new js_internal_storage;
  739. js_internal_storage *exprRes = doExpression(rootScope, remainingExpr);
  740. std::cout << "Expression tyoe[" << typeOfStorage(exprRes) << "]" << std::endl;
  741. if (typeOfStorage(exprRes) == "null")
  742. {
  743. stack = new js_internal_storage;
  744. } else {
  745. stack = exprRes;
  746. }
  747. */
  748. std::cout << "Done with creating new variable" << std::endl;
  749. continue;
  750. }
  751. jsDisplayScope(&rootScope, 0);
  752. std::cout << "is Not a Var\n";
  753. } else {
  754. // is an non-existant key
  755. }
  756. }
  757. }
  758. } else if (state == 1) {
  759. // in func call, double check the (
  760. if (it == "(") {
  761. state = 2;
  762. } else {
  763. std::cout << "doExpression1 - func call did not have (\n";
  764. std::cout << "doExpression1 - stack is [" << stack << "] will now have to set it to [" << callFunc << "]\n";
  765. stack = callFunc;
  766. state = 0;
  767. }
  768. } else if (state == 2) {
  769. params = it;
  770. state = 3;
  771. } else if (state == 3) {
  772. // in func call, double check the )
  773. if (it == ")") {
  774. /*
  775. js_function *jfunc = dynamic_cast<js_function*>(stack);
  776. if (!jfunc) {
  777. std::cout << "Could cast [" << stack << "] to func\n";
  778. continue;
  779. }
  780. */
  781. if (!callFunc) {
  782. std::cout << "HALT callFunc is null!\n";
  783. continue;
  784. }
  785. std::cout << "doExpression3 - calling [" << callFuncName << "](" << params << ") at [" << callFunc << "] with [" << callFunc->tokens.size() << "]tokens\n";
  786. stack = jsFunctionCall(callFuncName, callFunc, params, rootScope);
  787. state = 0;
  788. } else {
  789. std::cout << "doExpression3 - func call did not have (\n";
  790. std::cout << "doExpression3 - stack is [" << stack << "] will now have to set it to [" << callFunc << "]\n";
  791. stack = callFunc;
  792. state = 0;
  793. }
  794. } else if (state == 4) {
  795. js_internal_storage *expRes = doExpression(rootScope, it);
  796. // invert expRes;
  797. js_bool *jb = new js_bool;
  798. jb->value = !jsIsFalse(expRes);
  799. stack = jb;
  800. state = 0;
  801. } else if (state == 5) {
  802. /*
  803. js_function *objectScope = new js_function;
  804. js_object *newObject = new js_object;
  805. //doAssignment(*objectScope, it);
  806. parseJSON(*objectScope, it);
  807. // translate the scope into js_object
  808. //std::cout << "JSON object output" << std::endl;
  809. for(auto it2 : objectScope->locals.value) {
  810. //std::cout << "[" << it2.first << "=" << it2.second << "]" << std::endl;
  811. newObject->value[it2.first] = it2.second;
  812. }
  813. //std::cout << "JSON object done" << std::endl;
  814. stack = newObject;
  815. */
  816. stack = jsGetObject(rootScope, it);
  817. std::cout << "doExpression getObject got [" << stack << "]\n";
  818. state = 0;
  819. } else {
  820. std::cout << "doExpression unknown state[" << std::to_string(state) << "]\n";
  821. }
  822. }
  823. // FIXME: any remainder?
  824. if (state == 1) {
  825. // x = func ref that's never called
  826. std::cout << "doExpressionEND1 - func call did not have (\n";
  827. std::cout << "doExpressionEND1 - stack is [" << stack << "] will now have to set it to [" << callFunc << "]\n";
  828. stack = callFunc;
  829. state = 0;
  830. }
  831. if (state != 0) {
  832. std::cout << "doExpression final state[" << std::to_string(state) << "]\n";
  833. }
  834. return stack;
  835. }
  836. size_t findClosing(std::string token, size_t start, char open, char close) {
  837. std::cout << "\nfindClosing start[" << token.substr(start) << "]\n";
  838. size_t parenLevel = 0;
  839. for (size_t cursor = start; cursor < token.length(); cursor++) {
  840. std::cout << "findClosing scanning[" << token[cursor] << "] at[" << cursor << "/" << token.length() << "] parenLevel[" << parenLevel << "]\n";
  841. if (token[cursor] == open) {
  842. parenLevel++;
  843. } else
  844. if (token[cursor] == close) {
  845. parenLevel--;
  846. if (!parenLevel) {
  847. return cursor;
  848. }
  849. }
  850. }
  851. std::cout << "findClosing - HALT didnt find closing element[" << close << "]\n";
  852. return token.length();
  853. }
  854. // start is right after the "function" 8
  855. size_t locateFunctionNameEnd(std::string source, size_t start) {
  856. std::cout << "\nlocateFunctionNameEnd start[" << source.substr(start) << "]\n";
  857. for (size_t cursor = start; cursor < source.length(); cursor++) {
  858. if (source[cursor] == '(') {
  859. return cursor;
  860. }
  861. }
  862. std::cout << "locateFunctionNameEnd - HALT didnt find start paren for function\n";
  863. return source.length();
  864. }
  865. // start is right after the "function name(" 8
  866. size_t locateFunctionParamsEnd(std::string source, size_t start) {
  867. std::cout << "\nlocateFunctionParamsEnd start[" << source.substr(start) << "]\n";
  868. for (size_t cursor = start; cursor < source.length(); cursor++) {
  869. if (source[cursor] == '{') {
  870. return cursor;
  871. }
  872. }
  873. std::cout << "locateFunctionParamsEnd - HALT didnt find start brace for function\n";
  874. return source.length();
  875. }
  876. size_t locateSingleQuoteEnd(const std::string source, const size_t start) {
  877. for (size_t cursor = start; cursor < source.length(); cursor++) {
  878. if (source[cursor] == '\'') {
  879. if (source[cursor - 1] != '\\') {
  880. return cursor;
  881. }
  882. }
  883. }
  884. return start;
  885. }
  886. size_t locateDoubleQuoteEnd(const std::string source, const size_t start) {
  887. for (size_t cursor = start; cursor < source.length(); cursor++) {
  888. if (source[cursor] == '"') {
  889. if (source[cursor - 1] != '\\') {
  890. return cursor;
  891. }
  892. }
  893. }
  894. return start;
  895. }
  896. // well a regex is like a variable, can only be right side
  897. // where a divide is between two variables
  898. // can't start on the /
  899. // also could be division
  900. // end on the / or the last modifier (/x/g)
  901. size_t locateRegexEnd(const std::string source, const size_t start) {
  902. size_t adj = 0;
  903. if (source[start]=='/') {
  904. std::cout << "WARNING starting locateRegexEnd on /\n";
  905. adj = 1;
  906. }
  907. std::cout << "locateRegexEnd start [" << source.substr(start) << "]\n";
  908. unsigned char state = 0;
  909. for (size_t cursor = start + adj; cursor < source.length(); cursor++) {
  910. std::cout << "locateRegexEnd step [" << cursor << "/" << source.length() << "] char[" << source[cursor] << "] state[" << std::to_string(state) << "]\n";
  911. switch(state) {
  912. case 0:
  913. if (source[cursor] == '/') {
  914. if (source[cursor - 1] != '\\') {
  915. state = 1;
  916. }
  917. }
  918. // we need to search until the end of the string for any potential closing element
  919. break;
  920. case 1:
  921. // ,;\n
  922. switch(source[cursor]) {
  923. case '.': // regex obj
  924. return cursor - 1;
  925. case ',':
  926. return cursor - 1;
  927. break;
  928. case ';':
  929. return cursor - 1;
  930. break;
  931. case '\n':
  932. return cursor - 1;
  933. break;
  934. case ')':
  935. return cursor - 1;
  936. break;
  937. case '}':
  938. return cursor - 1;
  939. break;
  940. }
  941. break;
  942. }
  943. }
  944. // could be division
  945. std::cout << "locateRegexEnd division?\n";
  946. // division confirmation
  947. state = 0;
  948. for (size_t cursor = start + adj; cursor < source.length(); cursor++) {
  949. std::cout << "locateRegexEnd divisionStep [" << cursor << "/" << source.length() << "] char[" << source[cursor] << "] state[" << std::to_string(state) << "]\n";
  950. switch(state) {
  951. case 0:
  952. if (source[cursor] == '/') {
  953. if (source[cursor - 1] != '\\') {
  954. state = 1;
  955. }
  956. }
  957. switch(source[cursor]) {
  958. case ',':
  959. return start;
  960. break;
  961. case ';':
  962. return start;
  963. break;
  964. case '\n':
  965. return start;
  966. break;
  967. // .)} ?
  968. }
  969. break;
  970. case 1:
  971. // ,;\n
  972. switch(source[cursor]) {
  973. case '.': // regex obj
  974. return cursor;
  975. break;
  976. case ',':
  977. return cursor;
  978. break;
  979. case ';':
  980. return cursor;
  981. break;
  982. case '\n':
  983. return cursor;
  984. break;
  985. case ')':
  986. return cursor - 1;
  987. break;
  988. case '}':
  989. return cursor - 1;
  990. break;
  991. }
  992. break;
  993. }
  994. }
  995. // what the hell is this...
  996. return start;
  997. }
  998. int getNextExpressionLevel = 0;
  999. // we return the terminator if ,;\n or )}
  1000. // if the expression is a function definition, then we return the () as part of it
  1001. // when returning a function block, it needs to end on the }
  1002. size_t getNextExpression(const std::string source, const size_t start) {
  1003. getNextExpressionLevel++;
  1004. std::cout << "\n" << std::string(getNextExpressionLevel * 2, ' ') << "getNextExpression(" << getNextExpressionLevel << ") start[" << source.substr(start) << "]\n";
  1005. unsigned char state = 0;
  1006. size_t parenLevel = 0;
  1007. size_t stateStart = 0;
  1008. for (size_t cursor = start; cursor < source.length(); cursor++) {
  1009. std::cout << std::string(getNextExpressionLevel * 2, ' ') << "getNextExpression(" << getNextExpressionLevel << ") scanning[" << source[cursor] << "] at[" << cursor << "/" << source.length() << "] state[" << std::to_string(state) << "] parenLevel[" << parenLevel << "]\n";
  1010. switch(state) {
  1011. case 0:
  1012. // start function call
  1013. if (source[cursor]=='(') {
  1014. parenLevel++;
  1015. stateStart = cursor;
  1016. state = 1;
  1017. } else
  1018. if (source[cursor]=='\'') {
  1019. state = 4;
  1020. } else
  1021. if (source[cursor]=='"') {
  1022. state = 5;
  1023. }
  1024. // detect function definition and recurse
  1025. if (source[cursor] == 'f' && source.length() > cursor + 7 && source[cursor + 1] == 'u'
  1026. && source[cursor + 2] == 'n' && source[cursor + 3] == 'c' && source[cursor + 4] == 't'
  1027. && source[cursor + 5] == 'i' && source[cursor + 6] == 'o' && source[cursor + 7] == 'n') {
  1028. size_t last = cursor;
  1029. // parse name
  1030. last = locateFunctionNameEnd(source, cursor);
  1031. // parse params
  1032. last = locateFunctionParamsEnd(source, last);
  1033. // you need to find first brace
  1034. // call parseFunctionBody
  1035. last = parseFunctionBody(source, last);
  1036. std::cout << std::string(getNextExpressionLevel * 2, ' ') << "getNextExpression(" << getNextExpressionLevel << ") parseFunctionBody last[" << source[last] << "] just extracted[" << source.substr(cursor, last - cursor + 1) << "]\n";
  1037. cursor = last + 1; // artificially inflact the end because we're going to strip it
  1038. }
  1039. // detect for
  1040. // and end expression after }
  1041. // start regex
  1042. if (source[cursor]=='/' && source.length() > cursor + 1 && source[cursor + 1] != '/') {
  1043. // is this a regex or division?
  1044. size_t next = locateRegexEnd(source, cursor + 1);
  1045. if (next != start) {
  1046. // was a regex
  1047. cursor = next;
  1048. } // else was division element
  1049. }
  1050. // start scope
  1051. if (source[cursor]=='{') {
  1052. parenLevel++;
  1053. state = 2;
  1054. }
  1055. // minification technique (or list of variables, still an end of an expression tho)
  1056. if (source[cursor]==',') {
  1057. getNextExpressionLevel--;
  1058. return cursor;
  1059. }
  1060. // normal expression ender
  1061. if (source[cursor]==';') {
  1062. getNextExpressionLevel--;
  1063. return cursor;
  1064. }
  1065. // modern experession ender
  1066. if (source[cursor]=='\n') {
  1067. getNextExpressionLevel--;
  1068. return cursor;
  1069. }
  1070. // this is the last expression in a function
  1071. if (source[cursor]=='}') {
  1072. getNextExpressionLevel--;
  1073. // -1 doesn't work if the previous call in this block was from parseFunctionBody
  1074. // but we need -1 when found a stray }
  1075. return cursor - 1; // need to include the end }
  1076. }
  1077. // this is the last element in a list
  1078. if (source[cursor]==')') {
  1079. getNextExpressionLevel--;
  1080. return cursor;
  1081. }
  1082. /// maybe && and || should be expression terminators too
  1083. break;
  1084. case 1: // inside a function call, (
  1085. // make sure function isn't in a quote
  1086. if (source[cursor]=='\'') {
  1087. cursor = locateSingleQuoteEnd(source, cursor + 1);
  1088. } else
  1089. if (source[cursor]=='"') {
  1090. cursor = locateDoubleQuoteEnd(source, cursor + 1);
  1091. }
  1092. // we can't do this because
  1093. // getNextExpression(1) start[!!e.tailSize&&(t=$.cls("replyContainer"),!(a=t[t.length-e.tailSize])||(a=$.cls("dateTime",a)[0],n=(0|e.lastUpdated/1e3)-+a.getAttribute("data-utc"),i=0|(Date.now()-e.lastUpdated)/1e3,n>i))}]
  1094. // after e.lastUpdated
  1095. // getNextExpression(1) scanning[/] at[192/267] state[1] parenLevel[3]
  1096. // locateRegexEnd start [1e3)-+a.getAttribute("data-utc"),i=0|(Date.now()-e.lastUpdated)/1e3,n>i))}]
  1097. // we're just not smart enough to tell if we're division or regex (left/right or middle)
  1098. // if we're right after the starting (, then we know we're a regex in all cases.
  1099. if (stateStart + 1 == cursor) {
  1100. // start regex
  1101. if (source[cursor]=='/') {
  1102. // is this a regex or division?
  1103. size_t next = locateRegexEnd(source, cursor + 1);
  1104. if (next != start) {
  1105. // was a regex
  1106. cursor = next;
  1107. } // else was division element
  1108. }
  1109. }
  1110. // (function() {})
  1111. // detect function definition and recurse
  1112. if (source[cursor] == 'f' && source.length() > cursor + 7 && source[cursor + 1] == 'u'
  1113. && source[cursor + 2] == 'n' && source[cursor + 3] == 'c' && source[cursor + 4] == 't'
  1114. && source[cursor + 5] == 'i' && source[cursor + 6] == 'o' && source[cursor + 7] == 'n') {
  1115. // parse name
  1116. cursor = locateFunctionNameEnd(source, cursor);
  1117. // parse params
  1118. cursor = locateFunctionParamsEnd(source, cursor);
  1119. // you need to find first brace
  1120. // call parseFunctionBody
  1121. cursor = parseFunctionBody(source, cursor);
  1122. std::cout << std::string(getNextExpressionLevel * 2, ' ') << "getNextExpression - after parseFunctionBody now at " << cursor << "/" << source.length() << " char[" << source[cursor] << "] prev[" << source[cursor - 1] << "]\n";
  1123. }
  1124. // find end of function call
  1125. if (source[cursor] == '(') {
  1126. parenLevel++;
  1127. } else
  1128. if (source[cursor] == ')') {
  1129. parenLevel--;
  1130. if (!parenLevel) {
  1131. // while nothing can happen after a function call
  1132. // we need to process the terminating ,; or \n
  1133. state = 0;
  1134. }
  1135. }
  1136. break;
  1137. case 2:
  1138. // find end of scope
  1139. if (source[cursor] == '{') {
  1140. parenLevel++;
  1141. } else
  1142. if (source[cursor] == '}') {
  1143. parenLevel--;
  1144. if (!parenLevel) {
  1145. state = 0;
  1146. }
  1147. }
  1148. break;
  1149. case 4:
  1150. if (source[cursor] == '\'') {
  1151. if (source[cursor - 1] != '\\') {
  1152. //quoteEnd = cursor - 1;
  1153. state = 0;
  1154. }
  1155. }
  1156. break;
  1157. case 5:
  1158. if (source[cursor] == '"') {
  1159. if (source[cursor - 1] != '\\') {
  1160. //quoteEnd = cursor - 1;
  1161. state = 0;
  1162. }
  1163. }
  1164. break;
  1165. }
  1166. }
  1167. std::cout << std::string(getNextExpressionLevel * 2, ' ') << "getNextExpression[" << source.substr(start) << "] - WARNING didnt find another expression\n";
  1168. return source.length();
  1169. }
  1170. // also finishing character would be good to return
  1171. // we just need to find the start and ends, we don't need to parse contents
  1172. // we'll parse contents on execution
  1173. // sometimes the token starts at function()
  1174. // othertimes inside function
  1175. // we're supposed to be parsing a function definition
  1176. // ok we should only parse function bodies after the parameters
  1177. // so no () unless after
  1178. // so do we start at { or right before? well we don't need to...
  1179. // start should be after {?
  1180. // we should return a character that points to }
  1181. size_t parseFunctionBodyLevel = 0;
  1182. size_t parseFunctionBody(std::string source, size_t start) {
  1183. parseFunctionBodyLevel++;
  1184. std::cout << "\nparseFunctionBody(" << parseFunctionBodyLevel << ") start[" << source.substr(start) << "] next8[" << source.substr(start, 8) << "]\n";
  1185. size_t state = 0;
  1186. size_t parenLevel = 0;
  1187. //size_t last = start ? start - 1 : 0;
  1188. for (size_t cursor = start; cursor < source.length(); cursor++) {
  1189. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") scanning[" << source[cursor] << "] at[" << cursor << "/" << source.length() << "] state[" << std::to_string(state) << "]\n";
  1190. switch(state) {
  1191. case 0: // look for function body start
  1192. if (source[cursor] == '{') {
  1193. std::cout << "detected{ at" << " cursor " << cursor << std::endl;
  1194. // there really shouldn't be anything between ) and {
  1195. parenLevel++;
  1196. //last = cursor + 1;
  1197. state = 1;
  1198. //cursor = findClosing(source, cursor, '{', '}');
  1199. // FIXME: take function string and send it to a tokenizer
  1200. // save tokens to func.tokens
  1201. //expression_parts.push_back("{");
  1202. //return cursor;
  1203. }
  1204. break;
  1205. case 1:
  1206. // we're not done with outer function, but we are with the inner
  1207. /*
  1208. if (source[cursor] == '}') {
  1209. parenLevel--;
  1210. if (!parenLevel) {
  1211. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") PRE final} [" << source.substr(start, cursor + 1 - start) << "]\n";
  1212. parseFunctionBodyLevel--;
  1213. return cursor; // return a character ending on } according to spec
  1214. }
  1215. }
  1216. */
  1217. // what we can enter that has {
  1218. // well a function
  1219. // so we need to step expression by expression tbh
  1220. size_t next = getNextExpression(source, cursor);
  1221. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") - state1 start[" << cursor << "] next[" << next << "]\n";
  1222. if (next < cursor) next = cursor; // advanced at least 1 char
  1223. std::string exp = source.substr(cursor, next + 1 - cursor);
  1224. exp = trim(exp);
  1225. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") - NextExpression [" << exp << "]\n";
  1226. // we're basically looking for a next expression of {
  1227. /*
  1228. if (exp.length() == 0) {
  1229. return cursor;
  1230. }
  1231. */
  1232. if (exp.length() == 1) {
  1233. if (exp == "{") {
  1234. parenLevel++;
  1235. } else
  1236. if (exp == "}") {
  1237. parenLevel--;
  1238. if (!parenLevel) {
  1239. // this doesn't mean the function is over
  1240. // how it can it not, we have equal amounts of level
  1241. // well the levels aren't at the character level
  1242. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") final} [" << source.substr(start, next + 1 - start) << "]\n";
  1243. parseFunctionBodyLevel--;
  1244. return next; // return a character ending on } according to spec
  1245. }
  1246. }
  1247. }
  1248. // FIXME: kind of an ugly hack
  1249. // can't just be () because the expression could just be a call itself
  1250. // needs to be }()
  1251. if (exp.length() > 2) {
  1252. std::string last3 = exp.substr(exp.length() - 3, 3);
  1253. std::cout << "last3[" << last3 << "]\n";
  1254. if (last3 == "}()") {
  1255. // function declartion & call
  1256. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") final}() [" << source.substr(start, cursor + 1 - start) << "]\n";
  1257. parseFunctionBodyLevel--;
  1258. return cursor;
  1259. }
  1260. }
  1261. cursor = next;
  1262. std::cout << "parseFunctionBody1(" << parseFunctionBodyLevel << ") now at " << cursor << "/" << source.length() << " char[" << source[cursor] << "]\n";
  1263. if (cursor == source.length() - 1) {
  1264. // we just ended on
  1265. if (source[cursor]=='}') {
  1266. parseFunctionBodyLevel--;
  1267. return cursor;
  1268. }
  1269. }
  1270. /*
  1271. if (source[cursor] == '{') {
  1272. parenLevel++;
  1273. } else
  1274. if (source[cursor] == '}') {
  1275. parenLevel--;
  1276. if (!parenLevel) {
  1277. return cursor;
  1278. }
  1279. }
  1280. */
  1281. break;
  1282. }
  1283. }
  1284. parseFunctionBodyLevel--;
  1285. std::cout << "parseFunctionBody(" << parseFunctionBodyLevel << ") - HALT didnt find closing element for function\n";
  1286. return source.length();
  1287. /*
  1288. //jsGetTokens will tokenize the entire body of the function
  1289. // and return it as one token
  1290. std::vector<std::string> tokens = jsGetTokens(source, start + 1); // +1 to skip {
  1291. std::cout << "\nparseFunctionBody - jsGetTokens got " << tokens.size() << " tokens\n";
  1292. for(auto it: tokens) {
  1293. std::cout << "[" << it << "]" "\n";
  1294. }
  1295. std::string funcBody = tokens[0];
  1296. return start + funcBody.length();
  1297. */
  1298. }
  1299. // don't include the start { or ending }
  1300. // prototype doesn't include ()
  1301. js_function *makeFunctionFromString(const std::string body, const std::string prototype, js_function *parent) {
  1302. std::cout << "makeFunctionFromString [" << prototype << "][" << body << "]\n";
  1303. js_function *func = new js_function;
  1304. func->tokens = jsGetTokens(body, 0);
  1305. func->parameters = split(prototype, ',');
  1306. if (!func->tokens.size()) {
  1307. std::cout << "empty function?\n";
  1308. }
  1309. func->parentScope = parent;
  1310. return func;
  1311. }
  1312. js_array *jsGetArray(js_function &rootScope, std::string token) {
  1313. js_function *objectScope = new js_function;
  1314. js_array *jsArr = new js_array;
  1315. parseJSON(*objectScope, token);
  1316. for(auto it2 : objectScope->locals.value) {
  1317. jsArr->value.push_back(*it2.second);
  1318. }
  1319. return jsArr;
  1320. }
  1321. void parseArray(js_function &rootScope, std::string token) {
  1322. std::vector<std::string> json_keys;
  1323. std::vector<std::string> json_values;
  1324. size_t cursor;
  1325. size_t last = 0;
  1326. size_t quoteStart = 0;
  1327. size_t quoteEnd = 0;
  1328. size_t parenStart = 0;
  1329. size_t parenLevel = 0;
  1330. unsigned char state = 0;
  1331. for (cursor = 0; cursor < token.length(); cursor++) {
  1332. // we should only look for [:'"]
  1333. if (state == 0) {
  1334. switch(token[cursor]) {
  1335. // { or [ could be expression parsed I think...
  1336. case '\'':
  1337. quoteStart = cursor;
  1338. state = 4;
  1339. break;
  1340. case '"':
  1341. quoteStart = cursor;
  1342. state = 5;
  1343. break;
  1344. case ',':
  1345. std::string key = "";
  1346. if (quoteStart) {
  1347. // constant
  1348. key = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1349. } else {
  1350. // variable
  1351. key = token.substr(last, cursor - last);
  1352. }
  1353. key = trim(key);
  1354. std::cout << "element[" << key << "] quoted: " << quoteStart << std::endl;
  1355. json_keys.push_back(key);
  1356. last = cursor + 1;
  1357. state = 2;
  1358. quoteStart = 0;
  1359. quoteEnd = 0;
  1360. break;
  1361. }
  1362. } else if (state == 2) { // get value state
  1363. // now we haven't to make sure we don't enter {, } or function
  1364. // ', " are ok, but have to turn off parsing until we encounter the next
  1365. // a-zA-Z$ for variables assignment
  1366. switch(state) {
  1367. case 0:
  1368. switch(token[cursor]) {
  1369. case '{':
  1370. parenStart = cursor;
  1371. parenLevel++;
  1372. state = 1;
  1373. break;
  1374. case '[':
  1375. parenStart = cursor;
  1376. parenLevel++;
  1377. state = 2;
  1378. break;
  1379. case '\'':
  1380. quoteStart = cursor;
  1381. state = 4;
  1382. break;
  1383. case '"':
  1384. quoteStart = cursor;
  1385. state = 5;
  1386. break;
  1387. case ',':
  1388. std::string value = "";
  1389. if (quoteStart) {
  1390. value = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1391. } else {
  1392. value = token.substr(last, cursor - last);
  1393. value = trim(value);
  1394. }
  1395. std::cout << "value[" << value << "] quoted" << quoteStart << std::endl;
  1396. // JSON objects will already be assigned and empty
  1397. if (value != "") {
  1398. json_values.push_back(value);
  1399. js_string *newString = new js_string();
  1400. newString->value = value;
  1401. rootScope.locals.value[json_keys.back()] = newString;
  1402. }
  1403. last = cursor + 1;
  1404. state = 0;
  1405. quoteStart = 0;
  1406. quoteEnd = 0;
  1407. break;
  1408. }
  1409. break;
  1410. case 1:
  1411. switch(token[cursor]) {
  1412. case '{':
  1413. parenLevel++;
  1414. break;
  1415. case '}':
  1416. parenLevel--;
  1417. if (!parenLevel) {
  1418. std::string JSON = token.substr(parenStart + 1, cursor - parenStart);
  1419. std::cout << "PA Need to deJSON [" << JSON << "]" << std::endl;
  1420. /*
  1421. // well we can get a scope back
  1422. js_function *objectScope = new js_function;
  1423. parseJSON(*objectScope, JSON);
  1424. js_object *newObject = new js_object;
  1425. */
  1426. js_object *newObject = jsGetObject(rootScope, JSON);
  1427. rootScope.locals.value[json_keys.back()] = newObject;
  1428. last = cursor + 1;
  1429. state = 0;
  1430. }
  1431. break;
  1432. }
  1433. break;
  1434. case 2:
  1435. switch(token[cursor]) {
  1436. case '[':
  1437. parenLevel++;
  1438. break;
  1439. case ']':
  1440. parenLevel--;
  1441. if (!parenLevel) {
  1442. std::string arrStr = token.substr(parenStart + 1, cursor - parenStart);
  1443. std::cout << "Need to deArray [" << arrStr << "]" << std::endl;
  1444. // well we can get a scope back
  1445. js_function *objectScope = new js_function;
  1446. parseArray(*objectScope, arrStr);
  1447. js_object *newObject = new js_object;
  1448. rootScope.locals.value[json_keys.back()] = newObject;
  1449. last = cursor + 1;
  1450. state = 0;
  1451. }
  1452. break;
  1453. }
  1454. break;
  1455. case 4:
  1456. if (token[cursor] == '\'') {
  1457. if (token[cursor - 1] != '\\') {
  1458. quoteEnd = cursor - 1;
  1459. state = 0;
  1460. }
  1461. }
  1462. break;
  1463. case 5:
  1464. if (token[cursor] == '"') {
  1465. if (token[cursor - 1] != '\\') {
  1466. quoteEnd = cursor - 1;
  1467. state = 0;
  1468. }
  1469. }
  1470. break;
  1471. }
  1472. } else if (state == 4) {
  1473. if (token[cursor] == '\'') {
  1474. if (token[cursor - 1] != '\\') {
  1475. quoteEnd = cursor - 1;
  1476. state = 0;
  1477. }
  1478. }
  1479. } else if (state == 5) {
  1480. if (token[cursor] == '"') {
  1481. if (token[cursor - 1] != '\\') {
  1482. quoteEnd = cursor - 1;
  1483. state = 0;
  1484. }
  1485. }
  1486. }
  1487. }
  1488. }
  1489. js_object *jsGetObject(js_function &rootScope, std::string token) {
  1490. js_function *objectScope = new js_function;
  1491. js_object *jsonObj = new js_object;
  1492. parseJSON(*objectScope, token);
  1493. for(auto it2 : objectScope->locals.value) {
  1494. jsonObj->value[it2.first] = it2.second;
  1495. }
  1496. return jsonObj;
  1497. }
  1498. // we still need rootScope to read any vars from
  1499. // FIXME: take js_object and start
  1500. void parseJSON(js_function &rootScope, std::string token) {
  1501. std::vector<std::string> json_keys;
  1502. std::vector<std::string> json_values;
  1503. size_t cursor;
  1504. size_t last = 0;
  1505. size_t quoteStart = 0;
  1506. size_t quoteEnd = 0;
  1507. size_t parenStart = 0;
  1508. size_t parenLevel = 0;
  1509. unsigned char keyState = 0;
  1510. unsigned char valueState = 0;
  1511. std::cout << "parseJSON start[" << token << "]\n";
  1512. for (cursor = 0; cursor < token.length(); cursor++) {
  1513. std::cout << "parseJSON step cursor[" << cursor << "/" << token.length() << "] char[" << token[cursor] << "] keyState[" << std::to_string(keyState) << "] valueState[" << std::to_string(valueState) << "]\n";
  1514. if (keyState == 0) {
  1515. valueState = 0; // reset value state
  1516. switch(token[cursor]) {
  1517. case '\'':
  1518. quoteStart = cursor;
  1519. keyState = 4;
  1520. break;
  1521. case '"':
  1522. quoteStart = cursor;
  1523. keyState = 5;
  1524. break;
  1525. case ':':
  1526. std::string key = "";
  1527. if (quoteStart) {
  1528. key = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1529. } else {
  1530. key = token.substr(last, cursor - last);
  1531. }
  1532. key = trim(key);
  1533. std::cout << "parsingJSON - key[" << key << "] quoted: " << quoteStart << std::endl;
  1534. if (key == "prettyPrint") {
  1535. std::cout << "Found your shit, now step it\n";
  1536. }
  1537. json_keys.push_back(key);
  1538. last = cursor + 1;
  1539. keyState = 2;
  1540. quoteStart = 0;
  1541. quoteEnd = 0;
  1542. break;
  1543. }
  1544. } else if (keyState == 2) { // get value state
  1545. // now we haven't to make sure we don't enter {, } or function
  1546. // ', " are ok, but have to turn off parsing until we encounter the next
  1547. // a-zA-Z$ for variables assignment
  1548. // we should only look for [:'"]
  1549. //std::cout << "parseJSON ks2 looking at [" << token[cursor] << "] vs[" << std::to_string(valueState) << "]\n";
  1550. switch(valueState) {
  1551. case 0:
  1552. switch(token[cursor]) {
  1553. case 'f':
  1554. if (cursor + 7 < token.length()) {
  1555. std::string next8 = token.substr(cursor, 8);
  1556. //std::cout << "parsingJSON - isFunction [" << next8 << "]" << std::endl;
  1557. if (next8 == "function") {
  1558. cursor = locateFunctionNameEnd(token, cursor);
  1559. last = locateFunctionParamsEnd(token, cursor);
  1560. std::string prototype = token.substr(cursor + 1, last - cursor - 1);
  1561. cursor = last;
  1562. // you need to find first brace
  1563. last = parseFunctionBody(token, cursor);
  1564. if (token[last]!='}') {
  1565. // should end on }
  1566. // but should it be last + 1? definitely not
  1567. std::cout << "parsingJSON - parseFunctionBody broke spec, ending on [" << token[last] << "]\n";
  1568. }
  1569. //std::cout << "parseJSON last[" << token[last] << "]\n";
  1570. // + 1 to skip initial { and not + 1 because } and -1 because of that starting + 1
  1571. std::string funcContents = token.substr(cursor + 1, last - cursor - 1);
  1572. std::cout << "parsingJSON - function " << json_keys.back() << "[" << prototype << "] [" << funcContents << "]" << std::endl;
  1573. std::cout << "parsingJSON - current char [" << token[last] << "]\n";
  1574. cursor = last; // continue after } (for loop will advance this)
  1575. // we have this key now but we'll wait for the , to do it's thing
  1576. //valueState = 6;
  1577. json_values.push_back(funcContents);
  1578. // [" << funcContents << "]
  1579. assignfile << "JSON." << json_keys.back() << "=" << "_NTRFUNC0[" << funcContents.length() << "]" << "\n";
  1580. rootScope.locals.value[json_keys.back()] = makeFunctionFromString(funcContents, prototype, &rootScope);
  1581. valueState = 6;
  1582. //keyState = 0;
  1583. //valueState = 0;
  1584. }
  1585. }
  1586. break;
  1587. case '{':
  1588. parenStart = cursor;
  1589. parenLevel++;
  1590. valueState = 1;
  1591. break;
  1592. case '[':
  1593. parenStart = cursor;
  1594. parenLevel++;
  1595. valueState = 2;
  1596. break;
  1597. case '\'':
  1598. quoteStart = cursor;
  1599. valueState = 4;
  1600. break;
  1601. case '"':
  1602. quoteStart = cursor;
  1603. valueState = 5;
  1604. break;
  1605. case ',':
  1606. std::string value = "";
  1607. if (quoteStart) {
  1608. value = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1609. } else {
  1610. value = token.substr(last, cursor - last);
  1611. value = trim(value);
  1612. }
  1613. //std::cout << "parsingJSON - value[" << value << "] quoted" << quoteStart << std::endl;
  1614. // JSON objects will already be assigned and empty
  1615. if (value != "") {
  1616. json_values.push_back(value);
  1617. js_string *newString = new js_string();
  1618. newString->value = value;
  1619. assignfile << "JSON." << json_keys.back() << "=_NTRSTRING(,):'" << value << "'\n";
  1620. rootScope.locals.value[json_keys.back()] = newString;
  1621. } else {
  1622. if (quoteStart) {
  1623. // likely ""
  1624. json_values.push_back("");
  1625. js_string *newString = new js_string();
  1626. newString->value = "";
  1627. assignfile << "JSON." << json_keys.back() << "=_NTRSTRING(,):'" << value << "'\n";
  1628. rootScope.locals.value[json_keys.back()] = newString;
  1629. }
  1630. }
  1631. last = cursor + 1;
  1632. std::cout << "remainder last now points to[" << token[last] << "] should not be comma\n";
  1633. keyState = 0;
  1634. valueState = 0;
  1635. quoteStart = 0;
  1636. quoteEnd = 0;
  1637. break;
  1638. }
  1639. break;
  1640. case 1:
  1641. switch(token[cursor]) {
  1642. case '{':
  1643. parenLevel++;
  1644. break;
  1645. case '}':
  1646. parenLevel--;
  1647. if (!parenLevel) {
  1648. std::string JSON = token.substr(parenStart + 1, cursor - parenStart);
  1649. //std::cout << "parsingJSON - PJ Need to deJSON [" << JSON << "]" << std::endl;
  1650. // well we can get a scope back
  1651. /*
  1652. js_function *objectScope = new js_function;
  1653. parseJSON(*objectScope, JSON);
  1654. js_object *newObject = new js_object;
  1655. */
  1656. js_object *newObject = jsGetObject(rootScope, JSON);
  1657. assignfile << "JSON." << json_keys.back() << "=" << "_NTRJSON" << "\n";
  1658. rootScope.locals.value[json_keys.back()] = newObject;
  1659. last = cursor + 1;
  1660. valueState = 0;
  1661. // let keyState 2 finish it out
  1662. }
  1663. break;
  1664. }
  1665. break;
  1666. case 2:
  1667. switch(token[cursor]) {
  1668. case '[':
  1669. parenLevel++;
  1670. break;
  1671. case ']':
  1672. parenLevel--;
  1673. if (!parenLevel) {
  1674. std::string arrayStr = token.substr(parenStart + 1, cursor - parenStart);
  1675. //std::cout << "parsingJSON - Need to deArray [" << arrayStr << "]" << std::endl;
  1676. // well we can get a scope back
  1677. js_function *arrayScope = new js_function;
  1678. parseArray(*arrayScope, arrayStr);
  1679. js_array *newArray = new js_array;
  1680. assignfile << "JSON." << json_keys.back() << "=" << "_NTRARRAY" << "\n";
  1681. rootScope.locals.value[json_keys.back()] = newArray;
  1682. last = cursor + 1;
  1683. valueState = 0;
  1684. keyState = 0;
  1685. }
  1686. break;
  1687. }
  1688. break;
  1689. case 4:
  1690. if (token[cursor] == '\'') {
  1691. if (token[cursor - 1] != '\\') {
  1692. quoteEnd = cursor - 1;
  1693. valueState = 0;
  1694. }
  1695. }
  1696. break;
  1697. case 5:
  1698. if (token[cursor] == '"') {
  1699. if (token[cursor - 1] != '\\') {
  1700. quoteEnd = cursor - 1;
  1701. valueState = 0;
  1702. }
  1703. }
  1704. break;
  1705. case 6: // function push back
  1706. std::cout << "parseJSON state6 char[" << token[cursor] << "]\n";
  1707. if (token[cursor] == ',') {
  1708. /*
  1709. std::string value = "";
  1710. if (quoteStart) {
  1711. value = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1712. } else {
  1713. value = token.substr(last, cursor - last);
  1714. value = trim(value);
  1715. }
  1716. std::cout << "parsingJSON - value[" << value << "] quoted" << quoteStart << std::endl;
  1717. if (value != "") {
  1718. json_values.push_back(value);
  1719. assignfile << "JSON." << json_keys.back() << "=" << "_NTRFUNC6" << "\n";
  1720. rootScope.data[json_keys.back()] = func;
  1721. }
  1722. */
  1723. last = cursor + 1; // set to after the current character (next char after ,)
  1724. keyState = 0;
  1725. valueState = 0;
  1726. quoteStart = 0;
  1727. quoteEnd = 0;
  1728. } else if (token[cursor] == '}') {
  1729. // it's the end of the JSON
  1730. keyState = 0;
  1731. }
  1732. break;
  1733. }
  1734. } else if (keyState == 4) {
  1735. if (token[cursor] == '\'') {
  1736. if (token[cursor - 1] != '\\') {
  1737. quoteEnd = cursor - 1;
  1738. keyState = 0;
  1739. }
  1740. }
  1741. } else if (keyState == 5) {
  1742. if (token[cursor] == '"') {
  1743. if (token[cursor - 1] != '\\') {
  1744. quoteEnd = cursor - 1;
  1745. keyState = 0;
  1746. }
  1747. }
  1748. }
  1749. }
  1750. std::cout << "done parsingJSON keyState[" << std::to_string(keyState) << "] valueState[" << std::to_string(valueState) << "]\n";
  1751. // we can end safely if after a function, likely just the } left over
  1752. if (keyState == 2 && valueState != 6) {
  1753. std::string value = "";
  1754. if (quoteStart) {
  1755. value = token.substr(quoteStart + 1, quoteEnd - quoteStart); // skip the quotes
  1756. } else {
  1757. value = token.substr(last, cursor - last);
  1758. value = trim(value);
  1759. }
  1760. //std::cout << "parsingJSON - value[" << value << "] quoted" << quoteStart << std::endl;
  1761. // JSON objects will already be assigned and empty
  1762. if (value != "") {
  1763. json_values.push_back(value);
  1764. js_string *newString = new js_string();
  1765. newString->value = value;
  1766. assignfile << "JSON." << json_keys.back() << "=_NTRSTRING(END):'" << value << "'\n";
  1767. rootScope.locals.value[json_keys.back()] = newString;
  1768. }
  1769. }
  1770. std::cout << "exiting parseJSON with: \n";
  1771. jsDisplayScope(&rootScope, 0);
  1772. }
  1773. // return value is if there was any error (false for error, true for no error)
  1774. int doAssignmentLevel = 0;
  1775. bool doAssignment(js_function &rootScope, std::string token) {
  1776. doAssignmentLevel++;
  1777. // FIXME: make sure = isn't in quotes or JSON?
  1778. // FIXME: double or triple equal differentiation
  1779. //std::cout << "looking at [" << token << "]" << std::endl;
  1780. // document.documentElement.classList?($.hasClass=function(e,t){return e.classList.contains(t)},$.addClass=function(e,t){e.classList.add(t)},$.removeClass=function(e,t){e.classList.remove(t)}):($.hasClass=function(e,t){return-1!=(" "+e.className+" ").indexOf(" "+t+" ")},$.addClass=function(e,t){e.className=""===e.className?t:e.className+" "+t},$.removeClass=function(e,t){e.className=(" "+e.className+" ").replace(" "+t+" ","")})
  1781. std::vector<std::string> expression_parts;
  1782. size_t cursor;
  1783. size_t last = 0;
  1784. size_t quoteStart = 0;
  1785. size_t parenStart = 0;
  1786. size_t parenLevel = 0;
  1787. size_t trinaryLevel = 0;
  1788. unsigned char state = 0;
  1789. for (cursor = 0; cursor < token.length(); cursor++) {
  1790. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment(" << doAssignmentLevel << ") step [" << cursor << "/" << token.length() << "] char[" << token[cursor] << "] state[" << std::to_string(state) << "] parenLevel[" << parenLevel << "]\n";
  1791. if (state == 0) {
  1792. // =
  1793. // ||
  1794. // &&
  1795. // <, >, <=, >=, ==, ===, !=, !==
  1796. // +, -
  1797. // *, /, %
  1798. // ?, >>, <<
  1799. if (token[cursor] == 'f' && token.length() > cursor + 7 && token[cursor + 1] == 'u'
  1800. && token[cursor + 2] == 'n' && token[cursor + 3] == 'c' && token[cursor + 4] == 't'
  1801. && token[cursor + 5] == 'i' && token[cursor + 6] == 'o' && token[cursor + 7] == 'n') {
  1802. state = 3;
  1803. }
  1804. // if? yea we have to, otherwise it's scope becomes a JSON decode
  1805. // but that's not exactly a problem
  1806. // else?
  1807. if (token[cursor] == '\'') {
  1808. quoteStart = cursor;
  1809. state = 4;
  1810. } else
  1811. if (token[cursor] == '"') {
  1812. quoteStart = cursor;
  1813. state = 5;
  1814. } else
  1815. if (token[cursor] == '(') {
  1816. parenStart = cursor;
  1817. parenLevel++;
  1818. state = 8;
  1819. if (last != cursor) {
  1820. expression_parts.push_back(token.substr(last, cursor - last));
  1821. }
  1822. last = cursor + 1;
  1823. expression_parts.push_back("(");
  1824. } else
  1825. if (token[cursor] == '{') {
  1826. parenStart = cursor;
  1827. parenLevel++;
  1828. state = 1;
  1829. //std::cout << "last " << last << " cursor " << cursor << std::endl;
  1830. if (last != cursor) {
  1831. expression_parts.push_back(token.substr(last, cursor - last - 1));
  1832. }
  1833. last = cursor + 1;
  1834. expression_parts.push_back("{");
  1835. }
  1836. // single =
  1837. if (token[cursor] == '=' && token.length() > cursor + 1 && token[cursor + 1] != '=') {
  1838. //state = 1;
  1839. //std::cout << "starting = at " << cursor << " last: " << last << std::endl;
  1840. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1841. expression_parts.push_back("=");
  1842. }
  1843. // hack for JSON parsing
  1844. if (token[cursor] == ':') {
  1845. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1846. expression_parts.push_back("=");
  1847. state = 2;
  1848. }
  1849. // FIXME: pull out all the expression parsing stuff
  1850. // ||
  1851. if (token[cursor] == '|' && token.length() > cursor + 1 && token[cursor + 1] == '|') {
  1852. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1853. expression_parts.push_back("||");
  1854. cursor++;
  1855. }
  1856. if (token[cursor] == '&' && token.length() > cursor + 1 && token[cursor + 1] == '&') {
  1857. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1858. expression_parts.push_back("&&");
  1859. cursor++;
  1860. }
  1861. if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] != '=' && token[cursor + 1] != '>') {
  1862. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1863. expression_parts.push_back(">");
  1864. cursor++;
  1865. }
  1866. if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] != '=' && token[cursor + 1] != '<') {
  1867. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1868. expression_parts.push_back("<");
  1869. cursor++;
  1870. }
  1871. if (token[cursor] == '<' && token.length() > cursor + 1 && token[cursor + 1] == '=') {
  1872. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1873. expression_parts.push_back("<=");
  1874. cursor++;
  1875. }
  1876. if (token[cursor] == '>' && token.length() > cursor + 1 && token[cursor + 1] == '=') {
  1877. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1878. expression_parts.push_back(">=");
  1879. cursor++;
  1880. }
  1881. if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
  1882. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1883. expression_parts.push_back("==");
  1884. cursor++;
  1885. }
  1886. if (token[cursor] == '=' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
  1887. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
  1888. expression_parts.push_back("===");
  1889. cursor+=2;
  1890. }
  1891. if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] != '=') {
  1892. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 2;
  1893. expression_parts.push_back("!=");
  1894. cursor++;
  1895. }
  1896. if (token[cursor] == '!' && token.length() > cursor + 2 && token[cursor + 1] == '=' && token[cursor + 2] == '=') {
  1897. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 3;
  1898. expression_parts.push_back("!==");
  1899. cursor+=2;
  1900. }
  1901. // +
  1902. if (token[cursor] == '+') {
  1903. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1904. expression_parts.push_back("+");
  1905. } else
  1906. if (token[cursor] == '-') {
  1907. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1908. expression_parts.push_back("+");
  1909. } else
  1910. if (token[cursor] == '*') {
  1911. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1912. expression_parts.push_back("*");
  1913. } else
  1914. if (token[cursor] == '/') {
  1915. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1916. expression_parts.push_back("/");
  1917. } else
  1918. if (token[cursor] == '%') {
  1919. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1920. expression_parts.push_back("%");
  1921. } else
  1922. if (token[cursor] == '!') {
  1923. if (last != cursor) {
  1924. expression_parts.push_back(token.substr(last, cursor - last));
  1925. }
  1926. expression_parts.push_back("!"); last = cursor + 1;
  1927. } else
  1928. if (token[cursor] == '?') {
  1929. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1930. expression_parts.push_back("?");
  1931. trinaryLevel++;
  1932. state = 9;
  1933. } else if (token[cursor] == 'i' && token.length() > cursor + 2 && token[cursor + 1] == 'n' && token[cursor + 2] == ' ') {
  1934. // "property"in object (or new object)
  1935. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  1936. expression_parts.push_back("in");
  1937. }
  1938. } else if (state == 1) {
  1939. if (token[cursor] == '{') {
  1940. parenLevel++;
  1941. } else
  1942. if (token[cursor] == '}') {
  1943. parenLevel--;
  1944. if (!parenLevel) {
  1945. expression_parts.push_back(token.substr(last, cursor - last));
  1946. last = cursor + 1;
  1947. expression_parts.push_back("}");
  1948. state = 0;
  1949. }
  1950. }
  1951. } else if (state == 2) { // json state (can be moved)
  1952. if (token[cursor] == ',') {
  1953. expression_parts.push_back(token.substr(last, cursor - last));
  1954. last = cursor + 1;
  1955. state = 0;
  1956. }
  1957. } else if (state == 3) { // function start (can be moved)
  1958. if (token[cursor] == '{') {
  1959. // lets put the function prototype
  1960. expression_parts.push_back(token.substr(last, cursor - last));
  1961. last = cursor + 1;
  1962. size_t next = parseFunctionBody(token, cursor);
  1963. std::string funcBody = token.substr(cursor, 1 + next - cursor);
  1964. cursor = next;
  1965. std::cout << std::string(doAssignmentLevel * 2, ' ') << "parseFunctionBody returned[" << funcBody << "]\n";
  1966. //std::cout << "doAssignment3 parseFunctionBody last[" << token[cursor] << "]\n";
  1967. expression_parts.push_back(funcBody);
  1968. last = cursor + 1;
  1969. expression_parts.push_back("}"); // end function
  1970. state = 7; // move to execution/call check
  1971. //std::cout << "doAssignment - s3 - parenLevel: " << parenLevel << "\n";
  1972. //parenLevel++;
  1973. //state = 6; // move to the function body
  1974. }
  1975. } else if (state == 4) {
  1976. if (token[cursor] == '\'') {
  1977. if (token[cursor - 1] != '\\') {
  1978. //std::string quote = token.substr(quoteStart + 1, cursor - quoteStart - 1);
  1979. //expression_parts.push_back(quote);
  1980. //std::cout << "single quote: " << quote << std::endl;
  1981. state = 0;
  1982. }
  1983. }
  1984. } else if (state == 5) {
  1985. if (token[cursor] == '"') {
  1986. if (token[cursor - 1] != '\\') {
  1987. //std::string quote = token.substr(quoteStart + 1, cursor - quoteStart - 1);
  1988. //expression_parts.push_back(quote);
  1989. //std::cout << "double quote: " << quote << std::endl;
  1990. state = 0;
  1991. }
  1992. }
  1993. } else if (state == 6) {
  1994. // function body
  1995. // now regexes can have unbalanced {}
  1996. cursor = parseFunctionBody(token, cursor);
  1997. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 parseFunctionBody first[" << token[cursor] << "] last[" << token[last] << "]\n";
  1998. expression_parts.push_back(token.substr(last, cursor - last));
  1999. last = cursor + 1;
  2000. expression_parts.push_back("}"); // end function
  2001. state = 7;
  2002. /*
  2003. if (token[cursor] == '{') {
  2004. parenLevel++;
  2005. } else
  2006. if (token[cursor] == '}') {
  2007. parenLevel--;
  2008. if (!parenLevel) {
  2009. expression_parts.push_back(token.substr(last, cursor - last));
  2010. last = cursor + 1;
  2011. expression_parts.push_back("}"); // end function
  2012. state = 7;
  2013. }
  2014. }*/
  2015. } else if (state == 7) {
  2016. // cursor should be passed }
  2017. switch(token[cursor]) {
  2018. case '(':
  2019. if (!parenLevel) {
  2020. expression_parts.push_back("("); // start function call
  2021. }
  2022. parenLevel++;
  2023. break;
  2024. case ')':
  2025. parenLevel--;
  2026. if (!parenLevel) {
  2027. expression_parts.push_back(token.substr(last, cursor - last));
  2028. last = cursor + 1;
  2029. expression_parts.push_back(")"); // end function call
  2030. state = 0;
  2031. }
  2032. break;
  2033. case '\n':
  2034. last = cursor + 1;
  2035. state = 0;
  2036. break;
  2037. case ';':
  2038. last = cursor + 1;
  2039. state = 0;
  2040. break;
  2041. case ',':
  2042. last = cursor + 1;
  2043. state = 0;
  2044. break;
  2045. }
  2046. } else if (state == 8) {
  2047. if (token[cursor] == '(') {
  2048. parenLevel++;
  2049. } else
  2050. if (token[cursor] == ')') {
  2051. parenLevel--;
  2052. if (!parenLevel) {
  2053. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  2054. expression_parts.push_back(")");
  2055. state = 0;
  2056. }
  2057. }
  2058. } else if (state == 9) {
  2059. if (token[cursor] == '?') {
  2060. trinaryLevel++;
  2061. } else
  2062. if (token[cursor] == ':') {
  2063. trinaryLevel--;
  2064. if (!trinaryLevel) {
  2065. expression_parts.push_back(token.substr(last, cursor - last)); last = cursor + 1;
  2066. expression_parts.push_back(":");
  2067. state = 0;
  2068. }
  2069. }
  2070. }
  2071. }
  2072. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment ending state " << std::to_string(state) << std::endl;
  2073. if (last != token.length() && cursor != last) {
  2074. expression_parts.push_back(token.substr(last, token.length()));
  2075. if (state == 6) {
  2076. expression_parts.push_back("}");
  2077. }
  2078. }
  2079. std::cout << std::string(doAssignmentLevel * 2, ' ') << "expression string[" << token << "]" << std::endl;
  2080. std::cout << std::string(doAssignmentLevel * 2, ' ') << "expression debug" << std::endl;
  2081. std::string lastToken = "";
  2082. state = 0;
  2083. std::string left = "";
  2084. if (expression_parts.size() == 1) {
  2085. // usually just a variable declaration
  2086. std::string tLeft = trim(expression_parts[0]);
  2087. if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
  2088. //std::cout << "dequoting[" << tLeft << "]" << std::endl;
  2089. tLeft=tLeft.substr(1, tLeft.length() - 2);
  2090. }
  2091. std::cout << std::string(doAssignmentLevel * 2, ' ') << "Assigning (end) [" << tLeft << "]" << std::endl;
  2092. // we're just initialling a blank variable
  2093. js_internal_storage **storage = getObjectKeyPointer(tLeft, &rootScope);
  2094. if (storage != nullptr) {
  2095. storage = nullptr; // FIXME;
  2096. } else {
  2097. rootScope.locals.value[tLeft] = nullptr;
  2098. }
  2099. std::cout << std::string(doAssignmentLevel * 2, ' ') << "expression end" << std::endl << std::endl;
  2100. doAssignmentLevel--;
  2101. return true;
  2102. }
  2103. bool negate = false;
  2104. js_function *func = nullptr;
  2105. js_function *callFunc = nullptr;
  2106. std::string callFuncName = "";
  2107. std::string prototype = "";
  2108. std::string params = "";
  2109. js_internal_storage *stack = nullptr;
  2110. for(auto it : expression_parts) {
  2111. // probably should trim these
  2112. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment expression(" << doAssignmentLevel << ") token[" << it << "]" << std::to_string(state) << std::endl;
  2113. // default: put token in left, get op (usually =) and then get right side
  2114. std::string trimmedToken = trim(it);
  2115. if (state==0) {
  2116. negate = false;
  2117. prototype = "";
  2118. if (trimmedToken == "=") {
  2119. left = lastToken;
  2120. state = 1;
  2121. }
  2122. if (trimmedToken == "&&") {
  2123. // if stack is false...
  2124. std::cout << "stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
  2125. //return true;
  2126. }
  2127. // can actually go to 9 (include the space)
  2128. std::string first8 = trimmedToken.substr(0, 8);
  2129. if (first8 == "function") {
  2130. left = trimmedToken.substr(8);
  2131. // well it can be "function()"
  2132. // no left and no starting brace...
  2133. cursor = locateFunctionParamsEnd(left, 0);
  2134. if (cursor != 0) {
  2135. left = left.substr(0, cursor);
  2136. }
  2137. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment - function expr start Adjust left[" << left << "] to [" << left.substr(0, cursor) << "]\n";
  2138. state = 3;
  2139. }
  2140. // most likely a function call
  2141. // but also can be an expression
  2142. // (function() {}())
  2143. // token will matter here
  2144. // check for ()
  2145. if (trimmedToken == "(") {
  2146. state = 8;
  2147. }
  2148. } else if (state == 1) {
  2149. if (trimmedToken == "") continue; // skip empties, don't fire the assignment too early
  2150. if (it == " ") continue; // skip empties, don't fire the assignment too early
  2151. if (trimmedToken == "!") continue; // valid expression
  2152. if (trimmedToken == "}") continue; // valid part of an expression (why are we getting this, should have a starting { and be in state 2)
  2153. // so these next 2 execute a function that's on the stack
  2154. // state 0: elem =
  2155. // state 1: funcName,(,proto,),;
  2156. if (trimmedToken == "(") continue; // valid part of an expression
  2157. if (trimmedToken == ")") continue; // valid part of an expression
  2158. if (trimmedToken == "&&") {
  2159. // if stack is false...
  2160. std::cout << "state1 && stack[" << stack << "] stackIsFalse[" << jsIsFalse(stack) << "]\n";
  2161. if (jsIsFalse(stack)) {
  2162. // skip the rest of the expression
  2163. // set variable to false
  2164. std::string tLeft = trim(left);
  2165. if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
  2166. //std::cout << "dequoting[" << tLeft << "]" << std::endl;
  2167. tLeft=tLeft.substr(1, tLeft.length() - 2);
  2168. }
  2169. rootScope.locals.value[tLeft] = stack;
  2170. assignfile << tLeft << "=" << it << "\n";
  2171. std::cout << "doAssignment &&false final assign[" << tLeft << "]=false\n";
  2172. return true;
  2173. }
  2174. } // valid part of an expression
  2175. if (trimmedToken == "{") {
  2176. state = 2;
  2177. } else {
  2178. js_internal_storage *storage = doExpression(rootScope, trimmedToken);
  2179. if (storage) {
  2180. // state 1 can be an expression that we need to push the result onto the stack for && ||
  2181. stack = storage;
  2182. js_function *funcTest = dynamic_cast<js_function*>(storage);
  2183. if (funcTest) {
  2184. callFuncName = trimmedToken;
  2185. callFunc = funcTest;
  2186. state = 9;
  2187. continue;
  2188. }
  2189. std::string tLeft = trim(left);
  2190. if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
  2191. //std::cout << "dequoting[" << tLeft << "]" << std::endl;
  2192. tLeft=tLeft.substr(1, tLeft.length() - 2);
  2193. }
  2194. bool alreadySet = false;
  2195. size_t dotPos = tLeft.find('.');
  2196. if (dotPos != std::string::npos) {
  2197. js_internal_storage **key = getObjectKeyPointer(tLeft, &rootScope);
  2198. if (key != nullptr) {
  2199. alreadySet = true;
  2200. *key = storage;
  2201. }
  2202. }
  2203. if (!alreadySet) {
  2204. std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] storageFalse[" << jsIsFalse(storage) <<"] scope[" << &rootScope << "]\n";
  2205. rootScope.locals.value[tLeft] = storage;
  2206. jsDisplayScope(&rootScope, 0);
  2207. left = ""; // reset left
  2208. assignfile << tLeft << "=" << it << "\n";
  2209. }
  2210. } else {
  2211. std::cout << std::string(doAssignmentLevel * 2, ' ') << "HALT can't get value from [" << it << "]\n";
  2212. }
  2213. }
  2214. } else if (state == 2) {
  2215. js_object *newObject = jsGetObject(rootScope, it);
  2216. /*
  2217. js_function *objectScope = new js_function;
  2218. js_object *newObject = new js_object;
  2219. //doAssignment(*objectScope, it);
  2220. parseJSON(*objectScope, it);
  2221. // translate the scope into js_object
  2222. //std::cout << "JSON object output" << std::endl;
  2223. for(auto it2 : objectScope->locals.value) {
  2224. //std::cout << "[" << it2.first << "=" << it2.second << "]" << std::endl;
  2225. newObject->value[it2.first] = it2.second;
  2226. }
  2227. */
  2228. //std::cout << "JSON object done" << std::endl;
  2229. std::string tLeft = trim(left);
  2230. assignfile << tLeft << "=" << "_NTRJSON" << "\n";
  2231. rootScope.locals.value[tLeft] = newObject;
  2232. state = 0;
  2233. } else if (state == 3) { // started with state 1 function (we're in a function definition)
  2234. // function body
  2235. //std::cout << "function body[" << it << "]\n";
  2236. //func = new js_function;
  2237. // parse params
  2238. //cursor = locateFunctionParamsEnd(it, 0);
  2239. // you need to find first brace
  2240. // call parseFunctionBody
  2241. //last = parseFunctionBody(it, cursor);
  2242. //parseFunctionBody(it, 0, *func);
  2243. // + 1 to skip initial { and not + 1 because }
  2244. //func = makeFunctionFromString(it.substr(cursor + 1, cursor - last), &rootScope);
  2245. //std::cout << "doAssignment makeFunctionFromString start[" << it[0] << "] last[" << it[it.length() - 1] << "]\n";
  2246. std::string body = it.substr(1, it.length() - 2);
  2247. //std::cout << "doAssignment makeFunctionFromString2 start[" << body[0] << "] last[" << body[body.length() - 1] << "]\n";
  2248. func = makeFunctionFromString(body, prototype, &rootScope);
  2249. // we already have the body of the function
  2250. // we need to get this token (string that is the body of the function)
  2251. // into js_function
  2252. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment - creating function [" << left << "] with [" << func->tokens.size() << "]tokens\n";
  2253. // warning copy & paste
  2254. std::string tLeft = trim(left);
  2255. size_t dotPos = tLeft.find('.');
  2256. bool alreadySet = false;
  2257. if (dotPos != std::string::npos) {
  2258. //std::cout << "doAssignment - Key Has . \n";
  2259. std::string baseObj = tLeft.substr(0, dotPos);
  2260. //std::cout << "doAssignment - base[" << baseObj << "]" << std::endl;
  2261. js_internal_storage *baseStorage = jsLocateKey(&rootScope, baseObj);
  2262. if (baseStorage) {
  2263. std::string part2 = tLeft.substr(dotPos + 1);
  2264. //std::cout << "doAssignment - part2[" << part2 << "]" << std::endl;
  2265. js_object *jobj = dynamic_cast<js_object*>(baseStorage);
  2266. if (jobj) {
  2267. /*
  2268. if (jobj->value.find(part2) != jobj->value.end()) {
  2269. std::cout << "doAssignment - part2[" << part2 << "] is inside base" << std::endl;
  2270. //storage = jobj->value[part2]; // we will now point to this storage
  2271. } else {
  2272. std::cout << "doAssignment - part2[" << part2 << "] not in base" << std::endl;
  2273. for(auto it2 : jobj->value) {
  2274. std::cout << "[" << it2.first << "]\n";
  2275. }
  2276. }
  2277. */
  2278. assignfile << tLeft << "=" << "_NTRFUNC" << "\n";
  2279. jobj->value[part2] = func;
  2280. alreadySet = true;
  2281. } else {
  2282. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment - baseStorage couldn't be made a js_object. type[" << typeOfStorage(baseStorage) << "]\n";
  2283. }
  2284. //
  2285. //js_internal_storage *p2Storage = locateKey(&rootScope, value);
  2286. } else {
  2287. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment - Couldnt find base[" << baseObj << "] in scope" << std::endl;
  2288. }
  2289. }
  2290. if (!alreadySet) {
  2291. rootScope.locals.value[tLeft] = func;
  2292. }
  2293. state = 5;
  2294. } else if (state == 4) {
  2295. if (trimmedToken == "}") {
  2296. //displayScope(&rootScope, 0);
  2297. state = 5; // reset state
  2298. }
  2299. } else if (state == 5) { // function definition call check
  2300. // wait for ()
  2301. if (trimmedToken == "(") {
  2302. state = 6;
  2303. } else {
  2304. state = 0; // reset
  2305. }
  2306. } else if (state == 6) { // call function just defined
  2307. if (trimmedToken == ")") {
  2308. // parse/execute the tokens of said function
  2309. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - calling just defined function, tokens[" << func->tokens.size() << "]\n";
  2310. if (func->tokens.size()) {
  2311. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - calling just defined function, first token[" << func->tokens[0] << "]\n";
  2312. }
  2313. jsParseTokens(func->tokens, func);
  2314. state = 0; // reset
  2315. } else {
  2316. // collect params
  2317. std::cout << std::string(doAssignmentLevel * 2, ' ') << "doAssignment6 - WRITE ME collect params [" << it << "]\n";
  2318. }
  2319. } else if (state == 8) { // is a function call or expression
  2320. if (trimmedToken == ")") {
  2321. state = 0; // reset state
  2322. } else {
  2323. // call params
  2324. std::cout << std::string(doAssignmentLevel * 2, ' ') << "HALT need to parse these params[" << it << "]\n";
  2325. }
  2326. } else if (state == 9) { // are we a function call with return value, or assigning a function reference
  2327. js_internal_storage *storage = nullptr;
  2328. // we'll need a way to get tLeft back to set it
  2329. if (trimmedToken == "(") {
  2330. // it's a function call
  2331. // set state = 10 until we get all prototype
  2332. state = 10;
  2333. //storage = jsParseTokens(callFunc->tokens, callFunc);
  2334. } else {
  2335. // it's a function reference
  2336. storage = callFunc;
  2337. state = 0; // assuming end of this expression
  2338. }
  2339. if (storage) {
  2340. std::string tLeft = trim(left);
  2341. if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
  2342. //std::cout << "dequoting[" << tLeft << "]" << std::endl;
  2343. tLeft=tLeft.substr(1, tLeft.length() - 2);
  2344. }
  2345. bool alreadySet = false;
  2346. size_t dotPos = tLeft.find('.');
  2347. if (dotPos != std::string::npos) {
  2348. js_internal_storage **key = getObjectKeyPointer(tLeft, &rootScope);
  2349. if (key != nullptr) {
  2350. alreadySet = true;
  2351. *key = storage;
  2352. }
  2353. }
  2354. if (!alreadySet) {
  2355. std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] scope[" << &rootScope << "]\n";
  2356. rootScope.locals.value[tLeft] = storage;
  2357. jsDisplayScope(&rootScope, 0);
  2358. left = ""; // reset left
  2359. assignfile << tLeft << "=" << it << "\n";
  2360. }
  2361. }
  2362. } else if (state == 10) { // in function call params
  2363. if (trimmedToken == ")") {
  2364. // use doFunctionCall
  2365. js_internal_storage *storage = nullptr;
  2366. std::cout << "calling function [" << callFunc << "](" << params << ")\n";
  2367. storage = jsFunctionCall(callFuncName, callFunc, params, rootScope);
  2368. //storage = doFunctionCall(callFunc, params, rootScope);
  2369. std::cout << "function retval[" << storage << "] type[" << typeOfStorage(storage) << "]\n";
  2370. if (storage) {
  2371. std::string tLeft = trim(left);
  2372. if (tLeft[0]=='"' && tLeft[tLeft.length() - 1]=='"') {
  2373. //std::cout << "dequoting[" << tLeft << "]" << std::endl;
  2374. tLeft=tLeft.substr(1, tLeft.length() - 2);
  2375. }
  2376. bool alreadySet = false;
  2377. size_t dotPos = tLeft.find('.');
  2378. if (dotPos != std::string::npos) {
  2379. js_internal_storage **key = getObjectKeyPointer(tLeft, &rootScope);
  2380. if (key != nullptr) {
  2381. alreadySet = true;
  2382. *key = storage;
  2383. }
  2384. }
  2385. if (!alreadySet) {
  2386. std::cout << "doAssignment final assign[" << tLeft << "] of type[" << typeOfStorage(storage) << "] scope[" << &rootScope << "]\n";
  2387. rootScope.locals.value[tLeft] = storage;
  2388. jsDisplayScope(&rootScope, 0);
  2389. left = ""; // reset left
  2390. assignfile << tLeft << "=" << it << "\n";
  2391. }
  2392. }
  2393. state = 0;
  2394. } else {
  2395. // collect params
  2396. params = trimmedToken;
  2397. }
  2398. }
  2399. // { starts JSON capture (should be exactly one block before the } token)
  2400. // you create a scope for that variable and recurse
  2401. lastToken = it;
  2402. }
  2403. std::cout << std::string(doAssignmentLevel * 2, ' ') << "expression end, state " << std::to_string(state) << std::endl << std::endl;
  2404. //displayScope(&rootScope, 0);
  2405. /*
  2406. auto hasTripleEqual = token.find("===");
  2407. auto hasDoubleEqual = std::string::npos;
  2408. auto hasSingleEqual = std::string::npos;
  2409. if (hasTripleEqual == std::string::npos) {
  2410. hasDoubleEqual = token.find("==");
  2411. } else {
  2412. // process === expression
  2413. std::cout << "JSParser:::doAssignment - strict compare not implemented" << std::endl;
  2414. //std::cout << "token[" << token << "]" << std::endl;
  2415. }
  2416. if (hasDoubleEqual == std::string::npos) {
  2417. hasSingleEqual = token.find("=");
  2418. } else {
  2419. // process == expression
  2420. std::cout << "JSParser:::doAssignment - compare not implemented" << std::endl;
  2421. }
  2422. if (hasSingleEqual != std::string::npos) {
  2423. auto keyValue = split(token, '=');
  2424. if (keyValue.size() < 2) {
  2425. std::cout << "JSParser:::doAssignment - bad var parse " << keyValue[0] << std::endl;
  2426. return false;
  2427. }
  2428. // FIXME: dot notation in keys
  2429. auto key = trim(keyValue[0]);
  2430. // FIXME: is value a lambda
  2431. auto value = trim(keyValue[1]);
  2432. //std::cout << "[" << key << "=" << value << "]" << std::endl;
  2433. rootScope.variables[key] = value;
  2434. } else {
  2435. // var bob; just make sure the variable exists
  2436. rootScope.variables[token] = "";
  2437. }
  2438. */
  2439. doAssignmentLevel--;
  2440. return true;
  2441. }
  2442. js_internal_storage **getObjectKeyPointer(const std::string input, const js_function *scope) {
  2443. size_t dotPos = input.find('.');
  2444. if (dotPos != std::string::npos) {
  2445. std::cout << "getObjectKeyPointer - Key Has . scope[" << scope << "]\n";
  2446. std::string baseObj = input.substr(0, dotPos);
  2447. std::cout << "getObjectKeyPointer - base[" << baseObj << "]" << std::endl;
  2448. js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
  2449. if (baseStorage) {
  2450. std::string part2 = input.substr(dotPos + 1);
  2451. js_object *jobj = dynamic_cast<js_object*>(baseStorage);
  2452. // if not object, try ref and func
  2453. if (jobj == nullptr) {
  2454. js_reference *jref = dynamic_cast<js_reference*>(baseStorage);
  2455. if (jref) {
  2456. // try to cast it as an object
  2457. jobj = dynamic_cast<js_object*>(jref->ptr);
  2458. if (jobj == nullptr) {
  2459. // if not an object, try function
  2460. js_function *jfunc = dynamic_cast<js_function*>(jref->ptr);
  2461. if (jfunc) {
  2462. jobj = &jfunc->locals;
  2463. }
  2464. }
  2465. }
  2466. }
  2467. if (jobj) {
  2468. //jobj->value[part2] = storage;
  2469. //assignfile << "[" << baseObj << "].[" << part2 << "]=" << "\n";
  2470. //return true;
  2471. /*
  2472. std::cout << "getObjectKeyPointer - precheck\n";
  2473. for(auto it2 : jobj->value) {
  2474. std::cout << "getObjectKeyPointer - precheck key[" << it2.first << "] valueType [" << typeOfStorage(it2.second) << "]\n";
  2475. }
  2476. */
  2477. std::cout << "getObjectKeyPointer found base value[" << jobj->value[part2] << "] type[" << typeOfStorage(jobj->value[part2]) << "]\n";
  2478. if (jobj->value[part2] == nullptr) {
  2479. std::cout << "getObjectKeyPointer - NULL value\n";
  2480. for(auto it2 : jobj->value) {
  2481. std::string type = typeOfStorage(it2.second);
  2482. if (type == "string") {
  2483. js_string *string = dynamic_cast<js_string*>(it2.second);
  2484. std::cout << "getObjectKeyPointer - NULL key[" << it2.first << "] address[" << it2.second << "] stringValue[" << string->value << "]\n";
  2485. } else {
  2486. std::cout << "getObjectKeyPointer - NULL key[" << it2.first << "] address[" << it2.second << "] valueType [" << type << "]\n";
  2487. }
  2488. }
  2489. }
  2490. return &jobj->value[part2];
  2491. } else {
  2492. std::cout << "getObjectKeyPointer [" << baseObj << "] isnt an object\n";
  2493. // it's fine as long as the variable is defined
  2494. }
  2495. } else {
  2496. std::cout << "getObjectKeyPointer - Couldnt find base[" << baseObj << "] in scope" << std::endl;
  2497. jsDisplayScope(scope, 0);
  2498. }
  2499. } else {
  2500. // still check our scope for
  2501. }
  2502. return nullptr;
  2503. }
  2504. // we need the difference between base is there and not there
  2505. // dereferenceBaseExists
  2506. bool dereferenceHasBase(const std::string input, const js_function *scope) {
  2507. size_t dotPos = input.find('.');
  2508. if (dotPos != std::string::npos) {
  2509. std::string baseObj = input.substr(0, dotPos);
  2510. js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
  2511. if (baseStorage) {
  2512. return true;
  2513. }
  2514. }
  2515. dotPos = input.find('[');
  2516. if (dotPos != std::string::npos) {
  2517. size_t end = input.find(']');
  2518. if (end != std::string::npos) {
  2519. // we have an open and close
  2520. std::string baseObj = input.substr(0, dotPos);
  2521. js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
  2522. if (baseStorage) {
  2523. return true;
  2524. }
  2525. }
  2526. }
  2527. return false;
  2528. }
  2529. js_internal_storage *dereferenceObject(const std::string input, const js_function *scope) {
  2530. // FIXME: too simple, catches quoted strings with . in them
  2531. // FIXME: make sure we're not inside quotes
  2532. size_t dotPos = input.find('.');
  2533. if (dotPos != std::string::npos) {
  2534. std::string baseObj = input.substr(0, dotPos);
  2535. js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
  2536. if (baseStorage) {
  2537. std::string part2 = input.substr(dotPos + 1);
  2538. js_object *jobj = dynamic_cast<js_object*>(baseStorage);
  2539. if (jobj) {
  2540. if (jobj->value.find(part2) != jobj->value.end()) {
  2541. std::cout << "dereferenceObject - part2[" << part2 << "] is inside base" << std::endl;
  2542. return jobj->value[part2]; // we will now point to this storage
  2543. } else {
  2544. std::cout << "dereferenceObject - part2[" << part2 << "] not in base" << std::endl;
  2545. for(auto it2 : jobj->value) {
  2546. std::cout << "[" << it2.first << "]\n";
  2547. }
  2548. }
  2549. } else {
  2550. std::cout << "dereferenceObject - baseStorage couldn't be made a js_object. type[" << typeOfStorage(baseStorage) << "]\n";
  2551. // it's ok for a key to not exists in a defined variable
  2552. }
  2553. } else {
  2554. std::cout << "dereferenceObject - Couldnt find base[" << baseObj << "] in scope" << std::endl;
  2555. }
  2556. }
  2557. dotPos = input.find('[');
  2558. if (dotPos != std::string::npos) {
  2559. size_t end = input.find(']');
  2560. if (end != std::string::npos) {
  2561. // we have an open and close
  2562. std::string baseObj = input.substr(0, dotPos);
  2563. js_internal_storage *baseStorage = jsLocateKey(scope, baseObj);
  2564. if (baseStorage) {
  2565. std::string part2 = input.substr(dotPos + 1, end - dotPos - 1);
  2566. char lastChar = part2[part2.length() - 1];
  2567. // probably should run this through doExpression...
  2568. // FIXME: "asdf" + var + "zxcv"
  2569. if ((part2[0] == '"' && lastChar == '"') || (part2[0] == '\'' && lastChar == '\'')) {
  2570. js_object *jobj = dynamic_cast<js_object*>(baseStorage);
  2571. if (jobj) {
  2572. std::cout << "dereferenceObject bracket style <" << baseObj << ">[<" << part2 << "><" << input.substr(end) << ">\n";
  2573. // is constant
  2574. std::string constant = part2.substr(1, part2.length() - 2);
  2575. std::cout << "constant[" << constant << "]\n";
  2576. if (jobj->value.find(constant) != jobj->value.end()) {
  2577. std::cout << "dereferenceObject - constant[" << constant << "] is inside base" << std::endl;
  2578. return jobj->value[part2]; // we will now point to this storage
  2579. } else {
  2580. std::cout << "dereferenceObject - constant[" << constant << "] not in base" << std::endl;
  2581. for(auto it2 : jobj->value) {
  2582. std::cout << "[" << it2.first << "]\n";
  2583. }
  2584. }
  2585. } else {
  2586. std::cout << "dereferenceObject - baseStorage[" << baseObj << "] couldn't be made a js_object. type[" << typeOfStorage(baseStorage) << "]\n";
  2587. if (typeOfStorage(baseStorage) == "string") {
  2588. js_string *jstring = dynamic_cast<js_string *>(baseStorage);
  2589. std::cout << "baseStorage string value[" << jstring->value << "]\n";
  2590. }
  2591. }
  2592. } else {
  2593. // is variable
  2594. std::cout << "dereferenceObject bracket style HALT, expression dereference\n";
  2595. }
  2596. } else {
  2597. std::cout << "dereferenceObject - Couldnt find base[" << baseObj << "] in scope" << std::endl;
  2598. }
  2599. }
  2600. }
  2601. return nullptr;
  2602. }
  2603. // should return if we're halted or not...
  2604. js_internal_storage *jsParseTokens(const std::vector<std::string> &tokens, js_function *scope) {
  2605. // we need to at least build the root scope
  2606. //std::cout << "\nstart script" << std::endl;
  2607. js_internal_storage *stack = nullptr;
  2608. for(auto it : tokens) {
  2609. std::string ttoken = trim(it);
  2610. if (ttoken == "") continue; // skip empty tokens
  2611. std::cout << "parse token[" << it << "]" << std::endl;
  2612. if (ttoken.substr(0, 2)=="if") {
  2613. std::string ifStr = it.substr(2);
  2614. std::cout << "ifStr1[" << ifStr << "]" << std::endl;
  2615. // find (
  2616. size_t end = ifStr.find('(');
  2617. ifStr = ifStr.substr(end + 1); // skip the (
  2618. std::cout << "ifStr2[" << ifStr << "]" << std::endl;
  2619. // find )
  2620. // too simple, won't work if expression has a function call...
  2621. end = getNextExpression(ifStr, 0); // works great so far
  2622. //end = ifStr.find(')');
  2623. std::string ifCondition = ifStr.substr(0, end);
  2624. js_internal_storage *expRes = doExpression(*scope, ifCondition);
  2625. bool conditionRes = !jsIsFalse(expRes);
  2626. std::cout << "ifCondition[" << ifCondition << "] res[" << conditionRes << "]" << std::endl;
  2627. ifStr = ifStr.substr(0, end);
  2628. // then we'll use !isFalse to figure out if we need to exec this attached scope of code
  2629. // also don't forget about the else block and potentially elif
  2630. // FIXME: do we have a block start? yes but we won't have the other lines....
  2631. std::cout << "true block start search[" << ttoken.substr(3 + ifCondition.size()) << "]" << std::endl;
  2632. size_t start = ttoken.substr(3 + ifCondition.size()).find(')') + 3 + ifCondition.size() + 1; // after the )
  2633. end = parseFunctionBody(ttoken, start);
  2634. std::cout << "true block[" << ttoken.substr(start, end - start) << "]" << std::endl;
  2635. if (conditionRes) {
  2636. // a return in an if scope, would return from the function it's in
  2637. std::vector<std::string> tokens = jsGetTokens(ttoken, start);
  2638. js_internal_storage *val=jsParseTokens(tokens, scope);
  2639. std::cout << "value res[" << val << "]\n";
  2640. // skip all elses
  2641. } else {
  2642. // handle else
  2643. std::string lastToken = ttoken.substr(end);
  2644. std::cout << "looking for else [" << lastToken << "]\n";
  2645. if (lastToken[0] == '}') {
  2646. lastToken = ttoken.substr(end + 1);
  2647. std::cout << "Adjusted elseSearch past } [" << lastToken << "]\n";
  2648. }
  2649. start = lastToken.find("else");
  2650. if (start != std::string::npos) {
  2651. execfile << "if else not implemented\n";
  2652. std::cout << "false condition ELSE not implemented" << std::endl;
  2653. // would need to extract the else clause form lastToene
  2654. }
  2655. // now execute remaining code
  2656. // FIXME: there should be no expressions after an if statement
  2657. js_internal_storage *lastRes = doExpression(*scope, lastToken);
  2658. }
  2659. //std::cout << "HALT if not implemented" << std::endl;
  2660. //return nullptr;
  2661. } else if (ttoken.substr(0, 3)=="var") {
  2662. std::string listStr = it.substr(3);
  2663. // FIXME: , in quotes or {} (JSON) <= top priority for 4chan
  2664. std::vector<std::string> opens, closes;
  2665. opens.push_back("{");
  2666. opens.push_back("'");
  2667. opens.push_back("\"");
  2668. closes.push_back("}");
  2669. closes.push_back("'");
  2670. closes.push_back("\"");
  2671. auto varList = parseSepButNotBetween(listStr, ",", opens, closes);
  2672. //std::cout << "has " << varList.size() << " variables" << std::endl;
  2673. for(auto it2 : varList) {
  2674. //std::cout << "var processing [" << it2 << "]" << std::endl;
  2675. /*
  2676. // FIXME: make sure = isn't in quotes or JSON?
  2677. // FIXME: double or triple equal differentiation
  2678. //std::cout << "looking at [" << it2 << "]" << std::endl;
  2679. auto hasTripleEqual = it2.find("===");
  2680. auto hasDoubleEqual = std::string::npos;
  2681. auto hasSingleEqual = std::string::npos;
  2682. if (hasTripleEqual == std::string::npos) {
  2683. hasDoubleEqual = it2.find("==");
  2684. } else {
  2685. // process expression
  2686. std::cout << "var strict compare not implemented" << std::endl;
  2687. }
  2688. if (hasDoubleEqual == std::string::npos) {
  2689. hasSingleEqual = it2.find("=");
  2690. } else {
  2691. // process expression
  2692. std::cout << "var compare not implemented" << std::endl;
  2693. }
  2694. if (hasSingleEqual != std::string::npos) {
  2695. auto keyValue = split(it2, '=');
  2696. if (keyValue.size() < 2) {
  2697. std::cout << "bad var parse " << keyValue[0] << std::endl;
  2698. continue;
  2699. }
  2700. // FIXME: dot notation in keys
  2701. auto key = trim(keyValue[0]);
  2702. auto value = trim(keyValue[1]);
  2703. //std::cout << "[" << key << "=" << value <<s"]" << std::endl;
  2704. script->rootScope.variables[key] = value;
  2705. } else {
  2706. // var bob; just make sure the variable exists
  2707. script->rootScope.variables[it2] = "";
  2708. }
  2709. */
  2710. //std::cout << "About to assign, current scope: \n";
  2711. //displayScope(scope, 0);
  2712. execfile << "var - " << trim(it2) << " scope[" << scope << "]\n";
  2713. doAssignment(*scope, it2);
  2714. }
  2715. } else if (ttoken.substr(0, 9)=="function ") {
  2716. // ParseFunction
  2717. std::string defStr = it.substr(9);
  2718. // find ( (name end, prototype start)
  2719. size_t end = defStr.find('(');
  2720. std::string funcName = defStr.substr(0, end);
  2721. defStr = defStr.substr(end + 1); // next char after (
  2722. // find ) (prototype end)
  2723. end = defStr.find(')');
  2724. std::string prototype = defStr.substr(0, end);
  2725. defStr = defStr.substr(end + 1); // next char after )
  2726. // find { (func start)
  2727. end = defStr.find('{');
  2728. defStr = defStr.substr(end + 1, defStr.size() - 2); // from { to the end
  2729. //std::cout << "jsParseTokens Function Declartion start[" << defStr[0] << "] last[" << defStr[defStr.length() - 1] << "]\n";
  2730. auto funcTokens = jsGetTokens(defStr, 0);
  2731. //std::cout << "function [" << funcName << "] prototype [" << prototype << "] has [" << funcTokens.size() << "] tokens" << std::endl;
  2732. // __netrunner_function_definition is 31 chars
  2733. //scope->variables[funcName] = "__netrunner_function_definition = { prototype: \"" + prototype + "\", code: \"" + defStr + "\" }";
  2734. js_function *newFunc = new js_function;
  2735. newFunc->tokens = funcTokens;
  2736. newFunc->parentScope = scope;
  2737. scope->locals.value[funcName] = newFunc;
  2738. execfile << "function declaration [" << funcName << "](" << prototype << ") tokens[" << funcTokens.size() << "]\n";
  2739. } else if (ttoken.substr(0, 6)=="return") {
  2740. std::string afterReturn = ttoken.substr(7);
  2741. return doExpression(*scope, afterReturn);
  2742. } else if (ttoken.find("=") != std::string::npos) {
  2743. execfile << "assignment - " << it << "\n";
  2744. // has = so it's an expression
  2745. //std::cout << "assignment[" << it << "]" << std::endl;
  2746. //std::cout << "assignment not implemented" << std::endl;
  2747. doAssignment(*scope, it);
  2748. } else if (ttoken.find("(") != std::string::npos && ttoken.find(")") != std::string::npos) {
  2749. execfile << "function call\n";
  2750. // has () so it's a function call
  2751. //std::cout << "funcCall[" << it << "]" << std::endl;
  2752. // we need to start passed any && or ||
  2753. // need to parse any expression before the function call...
  2754. if (it.find("&&") == std::string::npos && it.find("||") == std::string::npos) {
  2755. // figure out function name
  2756. size_t parenStart = it.find("(");
  2757. std::string funcName = it.substr(0, parenStart);
  2758. //std::cout << "I think the function name is [" << funcName << "]" << std::endl;
  2759. std::string arguments = it.substr(parenStart + 1, it.find(")") - parenStart - 1);
  2760. //std::cout << "functionCall[" << funcName << "](" << arguments << ") not implemented" << std::endl;
  2761. execfile << "function call [" << funcName << "](" << arguments << ")\n";
  2762. js_internal_storage *storage = nullptr;
  2763. bool deref = dereferenceHasBase(funcName, scope);
  2764. if (deref) {
  2765. storage = dereferenceObject(funcName, scope);
  2766. }
  2767. // need to convert to storage to create js_function object
  2768. if (storage == nullptr) {
  2769. storage = jsLocateKey(scope, funcName);
  2770. }
  2771. if (storage == nullptr) {
  2772. std::cout << "HALT Function [" << funcName << "] d.n.e in this scope or parents, creating forwardCall" << std::endl;
  2773. jsDisplayScope(scope, 0);
  2774. return nullptr;
  2775. //scope->forwardCalls.push_back(funcName);
  2776. // we can't do much without the body of the function
  2777. } else {
  2778. js_function *func = dynamic_cast<js_function *>(storage);
  2779. if (!func) {
  2780. std::cout << "HALT Function [" << funcName << "] data isn't a function" << std::endl;
  2781. return nullptr;
  2782. }
  2783. // make sure function is parsed
  2784. // and step through tokens
  2785. // we should update the parameter values...
  2786. std::cout << "WARNING functionCall[" << funcName << "](" << arguments << ") parameters not implemented" << std::endl;
  2787. jsParseTokens(func->tokens, func);
  2788. //std::cout << "parameters[" << arguments << "]" << std::endl;
  2789. }
  2790. } else {
  2791. execfile << "function call - expression scope[" << scope << "]\n";
  2792. // we have an || or && instead ()
  2793. // window.clickable_ids&&document.addEventListener("4chanParsingDone",onParsingDone,!1)
  2794. // well it's technically an expression
  2795. // as long as we handle the && first
  2796. // then the left side before the right
  2797. // well fuck, lets tokenize left to right
  2798. stack = doExpression(*scope, it);
  2799. //std::cout << "HALT expression before functionCall not implemented [" << it << "]" << std::endl;
  2800. //return nullptr;
  2801. }
  2802. //std::cout << "functionCall not implemented" << std::endl;
  2803. } else {
  2804. std::cout << "jsParseTokens - unknown_type[" << it << "]" << std::endl;
  2805. }
  2806. }
  2807. return stack;
  2808. }
  2809. void JavaScript::parse(const std::string source) {
  2810. // tokenize source
  2811. //std::cout << "JavaScript::parse source[" << source << "]\n\n";
  2812. this->tokens = jsGetTokens(source, 0);
  2813. jsParseTokens(this->tokens, &this->rootScope);
  2814. }
  2815. void JavaScript::execute() {
  2816. // probably not needed because JS is executed as parsed in the browser
  2817. }
  2818. void JavaScript::append(const std::shared_ptr<JavaScript> &source) {
  2819. for(auto it : source->tokens) {
  2820. this->tokens.push_back(it);
  2821. }
  2822. }
  2823. void JavaScript::applyScope(const std::shared_ptr<JavaScript> &source) {
  2824. // merge scopes (instead of reparsing)
  2825. //std::cout << "JavaScript::append - merge scope" << std::endl;
  2826. for(auto it : source->rootScope.locals.value) {
  2827. //std::cout << "JavaScript::append - copying " << it.first << std::endl;
  2828. std::string type = typeOfStorage(it.second);
  2829. if (type == "reference") {
  2830. js_reference *srcRefDest = dynamic_cast<js_reference*>(it.second);
  2831. if (srcRefDest != nullptr) {
  2832. /*
  2833. bool found = false;
  2834. std::string sourceKey = "";
  2835. for(auto it2 : source->rootScope.locals.value) {
  2836. std::cout << "ptr[" << srcRefDest->ptr << "]==[" << it2.second << "]\n";
  2837. if (it2.second == srcRefDest->ptr) {
  2838. sourceKey = it2.first;
  2839. found = true;
  2840. break;
  2841. }
  2842. }
  2843. */
  2844. if (srcRefDest->ptr == &source->rootScope) {
  2845. //std::cout << "JavaScript::append - copying reference " << it.first << " points to root" << std::endl;
  2846. js_reference *trgRef = new js_reference; // FIXME: clean up somewhere
  2847. trgRef->ptr = &this->rootScope;
  2848. this->rootScope.locals.value[it.first] = trgRef;
  2849. } else {
  2850. std::string sourceKey = jsLocatePtrKey(&source->rootScope, srcRefDest->ptr);
  2851. if (sourceKey != "") {
  2852. std::cout << "JavaScript::append - WRITE ME copying reference " << it.first << " points to sourceKey[" << sourceKey << "] type[" << typeOfStorage(srcRefDest->ptr) << "]" << std::endl;
  2853. } else {
  2854. std::cout << "JavaScript::append - Reference[" << it.first << "] couldnt find reference\n";
  2855. }
  2856. }
  2857. } else {
  2858. std::cout << "JavaScript::append - Reference[" << it.first << "] doesnt point to a reference\n";
  2859. }
  2860. } else {
  2861. this->rootScope.locals.value[it.first] = it.second;
  2862. }
  2863. }
  2864. //std::cout << "JavaScript::append - after scope" << std::endl;
  2865. //jsDisplayScope(&this->rootScope, 0);
  2866. }