Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

JSParser.cpp 147KB

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