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 120KB

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