js.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258
  1. /*
  2. js.c -- Mini JavaScript
  3. Copyright (c) All Rights Reserved. See details at the end of the file.
  4. */
  5. /********************************** Includes **********************************/
  6. #include "js.h"
  7. #if ME_GOAHEAD_JAVASCRIPT
  8. /********************************** Defines ***********************************/
  9. #define OCTAL 8
  10. #define HEX 16
  11. static Js **jsHandles; /* List of js handles */
  12. static int jsMax = -1; /* Maximum size of */
  13. /****************************** Forward Declarations **************************/
  14. static Js *jsPtr(int jid);
  15. static void clearString(char **ptr);
  16. static void setString(char **ptr, cchar *s);
  17. static void appendString(char **ptr, cchar *s);
  18. static int parse(Js *ep, int state, int flags);
  19. static int parseStmt(Js *ep, int state, int flags);
  20. static int parseDeclaration(Js *ep, int state, int flags);
  21. static int parseCond(Js *ep, int state, int flags);
  22. static int parseExpr(Js *ep, int state, int flags);
  23. static int parseFunctionArgs(Js *ep, int state, int flags);
  24. static int evalExpr(Js *ep, cchar *lhs, int rel, cchar *rhs);
  25. static int evalCond(Js *ep, cchar *lhs, int rel, cchar *rhs);
  26. static int evalFunction(Js *ep);
  27. static void freeFunc(JsFun *func);
  28. static void jsRemoveNewlines(Js *ep, int state);
  29. static int getLexicalToken(Js *ep, int state);
  30. static int tokenAddChar(Js *ep, int c);
  31. static int inputGetc(Js *ep);
  32. static void inputPutback(Js *ep, int c);
  33. static int charConvert(Js *ep, int base, int maxDig);
  34. /************************************* Code ***********************************/
  35. PUBLIC int jsOpenEngine(WebsHash variables, WebsHash functions)
  36. {
  37. Js *ep;
  38. int jid, vid;
  39. if ((jid = wallocObject(&jsHandles, &jsMax, sizeof(Js))) < 0) {
  40. return -1;
  41. }
  42. ep = jsHandles[jid];
  43. ep->jid = jid;
  44. /*
  45. Create a top level symbol table if one is not provided for variables and functions. Variables may create other
  46. symbol tables for block level declarations so we use walloc to manage a list of variable tables.
  47. */
  48. if ((vid = wallocHandle(&ep->variables)) < 0) {
  49. jsMax = wfreeHandle(&jsHandles, ep->jid);
  50. return -1;
  51. }
  52. if (vid >= ep->variableMax) {
  53. ep->variableMax = vid + 1;
  54. }
  55. if (variables == -1) {
  56. ep->variables[vid] = hashCreate(64) + JS_OFFSET;
  57. ep->flags |= FLAGS_VARIABLES;
  58. } else {
  59. ep->variables[vid] = variables + JS_OFFSET;
  60. }
  61. if (functions == -1) {
  62. ep->functions = hashCreate(64);
  63. ep->flags |= FLAGS_FUNCTIONS;
  64. } else {
  65. ep->functions = functions;
  66. }
  67. jsLexOpen(ep);
  68. /*
  69. Define standard constants
  70. */
  71. jsSetGlobalVar(ep->jid, "null", NULL);
  72. return ep->jid;
  73. }
  74. PUBLIC void jsCloseEngine(int jid)
  75. {
  76. Js *ep;
  77. int i;
  78. if ((ep = jsPtr(jid)) == NULL) {
  79. return;
  80. }
  81. wfree(ep->error);
  82. ep->error = NULL;
  83. wfree(ep->result);
  84. ep->result = NULL;
  85. jsLexClose(ep);
  86. for (i = ep->variableMax - 1; i >= 0; i--) {
  87. if (ep->flags & FLAGS_VARIABLES) {
  88. hashFree(ep->variables[i] - JS_OFFSET);
  89. }
  90. ep->variableMax = wfreeHandle(&ep->variables, i);
  91. }
  92. if (ep->flags & FLAGS_FUNCTIONS) {
  93. hashFree(ep->functions);
  94. }
  95. jsMax = wfreeHandle(&jsHandles, ep->jid);
  96. wfree(ep);
  97. }
  98. #if !ECOS && KEEP
  99. PUBLIC char *jsEvalFile(int jid, char *path, char **emsg)
  100. {
  101. WebsStat sbuf;
  102. Js *ep;
  103. char *script, *rs;
  104. int fd;
  105. assert(path && *path);
  106. if (emsg) {
  107. *emsg = NULL;
  108. }
  109. if ((ep = jsPtr(jid)) == NULL) {
  110. return NULL;
  111. }
  112. if ((fd = open(path, O_RDONLY | O_BINARY, 0666)) < 0) {
  113. jsError(ep, "Bad handle %d", jid);
  114. return NULL;
  115. }
  116. if (stat(path, &sbuf) < 0) {
  117. close(fd);
  118. jsError(ep, "Cannot stat %s", path);
  119. return NULL;
  120. }
  121. if ((script = walloc(sbuf.st_size + 1)) == NULL) {
  122. close(fd);
  123. jsError(ep, "Cannot allocate %d", sbuf.st_size);
  124. return NULL;
  125. }
  126. if (read(fd, script, sbuf.st_size) != (int)sbuf.st_size) {
  127. close(fd);
  128. wfree(script);
  129. jsError(ep, "Error reading %s", path);
  130. return NULL;
  131. }
  132. script[sbuf.st_size] = '\0';
  133. close(fd);
  134. rs = jsEvalBlock(jid, script, emsg);
  135. wfree(script);
  136. return rs;
  137. }
  138. #endif
  139. /*
  140. Create a new variable scope block so that consecutive jsEval calls may be made with the same variable scope. This
  141. space MUST be closed with jsCloseBlock when the evaluations are complete.
  142. */
  143. PUBLIC int jsOpenBlock(int jid)
  144. {
  145. Js *ep;
  146. int vid;
  147. if((ep = jsPtr(jid)) == NULL) {
  148. return -1;
  149. }
  150. if ((vid = wallocHandle(&ep->variables)) < 0) {
  151. return -1;
  152. }
  153. if (vid >= ep->variableMax) {
  154. ep->variableMax = vid + 1;
  155. }
  156. ep->variables[vid] = hashCreate(64) + JS_OFFSET;
  157. return vid;
  158. }
  159. PUBLIC int jsCloseBlock(int jid, int vid)
  160. {
  161. Js *ep;
  162. if((ep = jsPtr(jid)) == NULL) {
  163. return -1;
  164. }
  165. hashFree(ep->variables[vid] - JS_OFFSET);
  166. ep->variableMax = wfreeHandle(&ep->variables, vid);
  167. return 0;
  168. }
  169. /*
  170. Create a new variable scope block and evaluate a script. All variables
  171. created during this context will be automatically deleted when complete.
  172. */
  173. PUBLIC char *jsEvalBlock(int jid, cchar *script, char **emsg)
  174. {
  175. char* returnVal;
  176. int vid;
  177. assert(script);
  178. vid = jsOpenBlock(jid);
  179. returnVal = jsEval(jid, script, emsg);
  180. jsCloseBlock(jid, vid);
  181. return returnVal;
  182. }
  183. /*
  184. Parse and evaluate Javascript.
  185. */
  186. PUBLIC char *jsEval(int jid, cchar *script, char **emsg)
  187. {
  188. Js *ep;
  189. JsInput *oldBlock;
  190. int state;
  191. void *endlessLoopTest;
  192. int loopCounter;
  193. assert(script);
  194. if (emsg) {
  195. *emsg = NULL;
  196. }
  197. if ((ep = jsPtr(jid)) == NULL) {
  198. return NULL;
  199. }
  200. setString(&ep->result, "");
  201. /*
  202. Allocate a new evaluation block, and save the old one
  203. */
  204. oldBlock = ep->input;
  205. jsLexOpenScript(ep, script);
  206. /*
  207. Do the actual parsing and evaluation
  208. */
  209. loopCounter = 0;
  210. endlessLoopTest = NULL;
  211. do {
  212. state = parse(ep, STATE_BEGIN, FLAGS_EXE);
  213. if (state == STATE_RET) {
  214. state = STATE_EOF;
  215. }
  216. /*
  217. prevent parser from going into infinite loop. If parsing the same line 10 times then fail and report Syntax
  218. error. Most normal error are caught in the parser itself.
  219. */
  220. if (endlessLoopTest == ep->input->script.servp) {
  221. if (loopCounter++ > 10) {
  222. state = STATE_ERR;
  223. jsError(ep, "Syntax error");
  224. }
  225. } else {
  226. endlessLoopTest = ep->input->script.servp;
  227. loopCounter = 0;
  228. }
  229. } while (state != STATE_EOF && state != STATE_ERR);
  230. jsLexCloseScript(ep);
  231. /*
  232. Return any error string to the user
  233. */
  234. if (state == STATE_ERR && emsg) {
  235. *emsg = sclone(ep->error);
  236. }
  237. /*
  238. Restore the old evaluation block
  239. */
  240. ep->input = oldBlock;
  241. if (state == STATE_EOF) {
  242. return ep->result;
  243. }
  244. if (state == STATE_ERR) {
  245. return NULL;
  246. }
  247. return ep->result;
  248. }
  249. /*
  250. Recursive descent parser for Javascript
  251. */
  252. static int parse(Js *ep, int state, int flags)
  253. {
  254. assert(ep);
  255. switch (state) {
  256. /*
  257. Any statement, function arguments or conditional expressions
  258. */
  259. case STATE_STMT:
  260. if ((state = parseStmt(ep, state, flags)) != STATE_STMT_DONE &&
  261. state != STATE_EOF && state != STATE_STMT_BLOCK_DONE &&
  262. state != STATE_RET) {
  263. state = STATE_ERR;
  264. }
  265. break;
  266. case STATE_DEC:
  267. if ((state = parseStmt(ep, state, flags)) != STATE_DEC_DONE &&
  268. state != STATE_EOF) {
  269. state = STATE_ERR;
  270. }
  271. break;
  272. case STATE_EXPR:
  273. if ((state = parseStmt(ep, state, flags)) != STATE_EXPR_DONE &&
  274. state != STATE_EOF) {
  275. state = STATE_ERR;
  276. }
  277. break;
  278. /*
  279. Variable declaration list
  280. */
  281. case STATE_DEC_LIST:
  282. state = parseDeclaration(ep, state, flags);
  283. break;
  284. /*
  285. Function argument string
  286. */
  287. case STATE_ARG_LIST:
  288. state = parseFunctionArgs(ep, state, flags);
  289. break;
  290. /*
  291. Logical condition list (relational operations separated by &&, ||)
  292. */
  293. case STATE_COND:
  294. state = parseCond(ep, state, flags);
  295. break;
  296. /*
  297. j Expression list
  298. */
  299. case STATE_RELEXP:
  300. state = parseExpr(ep, state, flags);
  301. break;
  302. }
  303. if (state == STATE_ERR && ep->error == NULL) {
  304. jsError(ep, "Syntax error");
  305. }
  306. return state;
  307. }
  308. /*
  309. Parse any statement including functions and simple relational operations
  310. */
  311. static int parseStmt(Js *ep, int state, int flags)
  312. {
  313. JsFun func;
  314. JsFun *saveFunc;
  315. JsInput condScript, endScript, bodyScript, incrScript;
  316. cchar *value;
  317. char *identifier;
  318. int done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags;
  319. int jsVarType;
  320. assert(ep);
  321. /*
  322. Set these to NULL, else we try to free them if an error occurs.
  323. */
  324. endScript.putBackToken = NULL;
  325. bodyScript.putBackToken = NULL;
  326. incrScript.putBackToken = NULL;
  327. condScript.putBackToken = NULL;
  328. expectSemi = 0;
  329. saveFunc = NULL;
  330. for (done = 0; !done; ) {
  331. tid = jsLexGetToken(ep, state);
  332. switch (tid) {
  333. default:
  334. jsLexPutbackToken(ep, TOK_EXPR, ep->token);
  335. done++;
  336. break;
  337. case TOK_ERR:
  338. state = STATE_ERR;
  339. done++;
  340. break;
  341. case TOK_EOF:
  342. state = STATE_EOF;
  343. done++;
  344. break;
  345. case TOK_NEWLINE:
  346. break;
  347. case TOK_SEMI:
  348. /*
  349. This case is when we discover no statement and just a lone ';'
  350. */
  351. if (state != STATE_STMT) {
  352. jsLexPutbackToken(ep, tid, ep->token);
  353. }
  354. done++;
  355. break;
  356. case TOK_ID:
  357. /*
  358. This could either be a reference to a variable or an assignment
  359. */
  360. identifier = NULL;
  361. setString(&identifier, ep->token);
  362. /*
  363. Peek ahead to see if this is an assignment
  364. */
  365. tid = jsLexGetToken(ep, state);
  366. if (tid == TOK_ASSIGNMENT) {
  367. if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
  368. clearString(&identifier);
  369. goto error;
  370. }
  371. if (flags & FLAGS_EXE) {
  372. if ( state == STATE_DEC ) {
  373. jsSetLocalVar(ep->jid, identifier, ep->result);
  374. } else {
  375. jsVarType = jsGetVar(ep->jid, identifier, &value);
  376. if (jsVarType > 0) {
  377. jsSetLocalVar(ep->jid, identifier, ep->result);
  378. } else {
  379. jsSetGlobalVar(ep->jid, identifier, ep->result);
  380. }
  381. }
  382. }
  383. } else if (tid == TOK_INC_DEC ) {
  384. value = NULL;
  385. if (flags & FLAGS_EXE) {
  386. jsVarType = jsGetVar(ep->jid, identifier, &value);
  387. if (jsVarType < 0) {
  388. jsError(ep, "Undefined variable %s\n", identifier);
  389. goto error;
  390. }
  391. setString(&ep->result, value);
  392. if (evalExpr(ep, value, (int) *ep->token, "1") < 0) {
  393. state = STATE_ERR;
  394. break;
  395. }
  396. if (jsVarType > 0) {
  397. jsSetLocalVar(ep->jid, identifier, ep->result);
  398. } else {
  399. jsSetGlobalVar(ep->jid, identifier, ep->result);
  400. }
  401. }
  402. } else {
  403. /*
  404. If we are processing a declaration, allow undefined vars
  405. */
  406. value = NULL;
  407. if (state == STATE_DEC) {
  408. if (jsGetVar(ep->jid, identifier, &value) > 0) {
  409. jsError(ep, "Variable already declared",
  410. identifier);
  411. clearString(&identifier);
  412. goto error;
  413. }
  414. jsSetLocalVar(ep->jid, identifier, NULL);
  415. } else {
  416. if ( flags & FLAGS_EXE ) {
  417. if (jsGetVar(ep->jid, identifier, &value) < 0) {
  418. jsError(ep, "Undefined variable %s\n",
  419. identifier);
  420. clearString(&identifier);
  421. goto error;
  422. }
  423. }
  424. }
  425. setString(&ep->result, value);
  426. jsLexPutbackToken(ep, tid, ep->token);
  427. }
  428. clearString(&identifier);
  429. if (state == STATE_STMT) {
  430. expectSemi++;
  431. }
  432. done++;
  433. break;
  434. case TOK_LITERAL:
  435. /*
  436. Set the result to the literal (number or string constant)
  437. */
  438. setString(&ep->result, ep->token);
  439. if (state == STATE_STMT) {
  440. expectSemi++;
  441. }
  442. done++;
  443. break;
  444. case TOK_FUNCTION:
  445. /*
  446. We must save any current ep->func value for the current stack frame
  447. */
  448. if (ep->func) {
  449. saveFunc = ep->func;
  450. }
  451. memset(&func, 0, sizeof(JsFun));
  452. setString(&func.fname, ep->token);
  453. ep->func = &func;
  454. setString(&ep->result, "");
  455. if (jsLexGetToken(ep, state) != TOK_LPAREN) {
  456. freeFunc(&func);
  457. ep->func = saveFunc;
  458. goto error;
  459. }
  460. if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) {
  461. freeFunc(&func);
  462. ep->func = saveFunc;
  463. goto error;
  464. }
  465. /*
  466. Evaluate the function if required
  467. */
  468. if (flags & FLAGS_EXE && evalFunction(ep) < 0) {
  469. freeFunc(&func);
  470. ep->func = saveFunc;
  471. goto error;
  472. }
  473. freeFunc(&func);
  474. ep->func = saveFunc;
  475. if (jsLexGetToken(ep, state) != TOK_RPAREN) {
  476. goto error;
  477. }
  478. if (state == STATE_STMT) {
  479. expectSemi++;
  480. }
  481. done++;
  482. break;
  483. case TOK_IF:
  484. if (state != STATE_STMT) {
  485. goto error;
  486. }
  487. if (jsLexGetToken(ep, state) != TOK_LPAREN) {
  488. goto error;
  489. }
  490. /*
  491. Evaluate the entire condition list "(condition)"
  492. */
  493. if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
  494. goto error;
  495. }
  496. if (jsLexGetToken(ep, state) != TOK_RPAREN) {
  497. goto error;
  498. }
  499. /*
  500. This is the "then" case. We need to always parse both cases and execute only the relevant case.
  501. */
  502. if (*ep->result == '1') {
  503. thenFlags = flags;
  504. elseFlags = flags & ~FLAGS_EXE;
  505. } else {
  506. thenFlags = flags & ~FLAGS_EXE;
  507. elseFlags = flags;
  508. }
  509. /*
  510. Process the "then" case. Allow for RETURN statement
  511. */
  512. switch (parse(ep, STATE_STMT, thenFlags)) {
  513. case STATE_RET:
  514. return STATE_RET;
  515. case STATE_STMT_DONE:
  516. break;
  517. default:
  518. goto error;
  519. }
  520. /*
  521. check to see if there is an "else" case
  522. */
  523. jsRemoveNewlines(ep, state);
  524. tid = jsLexGetToken(ep, state);
  525. if (tid != TOK_ELSE) {
  526. jsLexPutbackToken(ep, tid, ep->token);
  527. done++;
  528. break;
  529. }
  530. /*
  531. Process the "else" case. Allow for return.
  532. */
  533. switch (parse(ep, STATE_STMT, elseFlags)) {
  534. case STATE_RET:
  535. return STATE_RET;
  536. case STATE_STMT_DONE:
  537. break;
  538. default:
  539. goto error;
  540. }
  541. done++;
  542. break;
  543. case TOK_FOR:
  544. /*
  545. Format for the expression is:
  546. for (initial; condition; incr) {
  547. body;
  548. }
  549. */
  550. if (state != STATE_STMT) {
  551. goto error;
  552. }
  553. if (jsLexGetToken(ep, state) != TOK_LPAREN) {
  554. goto error;
  555. }
  556. /*
  557. Evaluate the for loop initialization statement
  558. */
  559. if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
  560. goto error;
  561. }
  562. if (jsLexGetToken(ep, state) != TOK_SEMI) {
  563. goto error;
  564. }
  565. /*
  566. The first time through, we save the current input context just to each step: prior to the conditional,
  567. the loop increment and the loop body.
  568. */
  569. jsLexSaveInputState(ep, &condScript);
  570. if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
  571. goto error;
  572. }
  573. cond = (*ep->result != '0');
  574. if (jsLexGetToken(ep, state) != TOK_SEMI) {
  575. goto error;
  576. }
  577. /*
  578. Don't execute the loop increment statement or the body first time
  579. */
  580. forFlags = flags & ~FLAGS_EXE;
  581. jsLexSaveInputState(ep, &incrScript);
  582. if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) {
  583. goto error;
  584. }
  585. if (jsLexGetToken(ep, state) != TOK_RPAREN) {
  586. goto error;
  587. }
  588. /*
  589. Parse the body and remember the end of the body script
  590. */
  591. jsLexSaveInputState(ep, &bodyScript);
  592. if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) {
  593. goto error;
  594. }
  595. jsLexSaveInputState(ep, &endScript);
  596. /*
  597. Now actually do the for loop. Note loop has been rotated
  598. */
  599. while (cond && (flags & FLAGS_EXE) ) {
  600. /*
  601. Evaluate the body
  602. */
  603. jsLexRestoreInputState(ep, &bodyScript);
  604. switch (parse(ep, STATE_STMT, flags)) {
  605. case STATE_RET:
  606. return STATE_RET;
  607. case STATE_STMT_DONE:
  608. break;
  609. default:
  610. goto error;
  611. }
  612. /*
  613. Evaluate the increment script
  614. */
  615. jsLexRestoreInputState(ep, &incrScript);
  616. if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
  617. goto error;
  618. }
  619. /*
  620. Evaluate the condition
  621. */
  622. jsLexRestoreInputState(ep, &condScript);
  623. if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
  624. goto error;
  625. }
  626. cond = (*ep->result != '0');
  627. }
  628. jsLexRestoreInputState(ep, &endScript);
  629. done++;
  630. break;
  631. case TOK_VAR:
  632. if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) {
  633. goto error;
  634. }
  635. done++;
  636. break;
  637. case TOK_COMMA:
  638. jsLexPutbackToken(ep, TOK_EXPR, ep->token);
  639. done++;
  640. break;
  641. case TOK_LPAREN:
  642. if (state == STATE_EXPR) {
  643. if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
  644. goto error;
  645. }
  646. if (jsLexGetToken(ep, state) != TOK_RPAREN) {
  647. goto error;
  648. }
  649. return STATE_EXPR_DONE;
  650. }
  651. done++;
  652. break;
  653. case TOK_RPAREN:
  654. jsLexPutbackToken(ep, tid, ep->token);
  655. return STATE_EXPR_DONE;
  656. case TOK_LBRACE:
  657. /*
  658. This handles any code in braces except "if () {} else {}"
  659. */
  660. if (state != STATE_STMT) {
  661. goto error;
  662. }
  663. /*
  664. Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen
  665. */
  666. do {
  667. state = parse(ep, STATE_STMT, flags);
  668. } while (state == STATE_STMT_DONE);
  669. /*
  670. Allow return statement.
  671. */
  672. if (state == STATE_RET) {
  673. return state;
  674. }
  675. if (jsLexGetToken(ep, state) != TOK_RBRACE) {
  676. goto error;
  677. }
  678. return STATE_STMT_DONE;
  679. case TOK_RBRACE:
  680. if (state == STATE_STMT) {
  681. jsLexPutbackToken(ep, tid, ep->token);
  682. return STATE_STMT_BLOCK_DONE;
  683. }
  684. goto error;
  685. case TOK_RETURN:
  686. if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
  687. goto error;
  688. }
  689. if (flags & FLAGS_EXE) {
  690. while ( jsLexGetToken(ep, state) != TOK_EOF );
  691. done++;
  692. return STATE_RET;
  693. }
  694. break;
  695. }
  696. }
  697. if (expectSemi) {
  698. tid = jsLexGetToken(ep, state);
  699. if (tid != TOK_SEMI && tid != TOK_NEWLINE) {
  700. goto error;
  701. }
  702. /*
  703. Skip newline after semi-colon
  704. */
  705. jsRemoveNewlines(ep, state);
  706. }
  707. doneParse:
  708. if (tid == TOK_FOR) {
  709. jsLexFreeInputState(ep, &condScript);
  710. jsLexFreeInputState(ep, &incrScript);
  711. jsLexFreeInputState(ep, &endScript);
  712. jsLexFreeInputState(ep, &bodyScript);
  713. }
  714. if (state == STATE_STMT) {
  715. return STATE_STMT_DONE;
  716. } else if (state == STATE_DEC) {
  717. return STATE_DEC_DONE;
  718. } else if (state == STATE_EXPR) {
  719. return STATE_EXPR_DONE;
  720. } else if (state == STATE_EOF) {
  721. return state;
  722. } else {
  723. return STATE_ERR;
  724. }
  725. error:
  726. state = STATE_ERR;
  727. goto doneParse;
  728. }
  729. /*
  730. Parse variable declaration list
  731. */
  732. static int parseDeclaration(Js *ep, int state, int flags)
  733. {
  734. int tid;
  735. assert(ep);
  736. /*
  737. Declarations can be of the following forms:
  738. var x;
  739. var x, y, z;
  740. var x = 1 + 2 / 3, y = 2 + 4;
  741. We set the variable to NULL if there is no associated assignment.
  742. */
  743. do {
  744. if ((tid = jsLexGetToken(ep, state)) != TOK_ID) {
  745. return STATE_ERR;
  746. }
  747. jsLexPutbackToken(ep, tid, ep->token);
  748. /*
  749. Parse the entire assignment or simple identifier declaration
  750. */
  751. if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) {
  752. return STATE_ERR;
  753. }
  754. /*
  755. Peek at the next token, continue if comma seen
  756. */
  757. tid = jsLexGetToken(ep, state);
  758. if (tid == TOK_SEMI) {
  759. return STATE_DEC_LIST_DONE;
  760. } else if (tid != TOK_COMMA) {
  761. return STATE_ERR;
  762. }
  763. } while (tid == TOK_COMMA);
  764. if (tid != TOK_SEMI) {
  765. return STATE_ERR;
  766. }
  767. return STATE_DEC_LIST_DONE;
  768. }
  769. /*
  770. Parse function arguments
  771. */
  772. static int parseFunctionArgs(Js *ep, int state, int flags)
  773. {
  774. int tid, aid;
  775. assert(ep);
  776. do {
  777. state = parse(ep, STATE_RELEXP, flags);
  778. if (state == STATE_EOF || state == STATE_ERR) {
  779. return state;
  780. }
  781. if (state == STATE_RELEXP_DONE) {
  782. aid = wallocHandle(&ep->func->args);
  783. ep->func->args[aid] = sclone(ep->result);
  784. ep->func->nArgs++;
  785. }
  786. /*
  787. Peek at the next token, continue if more args (ie. comma seen)
  788. */
  789. tid = jsLexGetToken(ep, state);
  790. if (tid != TOK_COMMA) {
  791. jsLexPutbackToken(ep, tid, ep->token);
  792. }
  793. } while (tid == TOK_COMMA);
  794. if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) {
  795. return STATE_ERR;
  796. }
  797. return STATE_ARG_LIST_DONE;
  798. }
  799. /*
  800. Parse conditional expression (relational ops separated by ||, &&)
  801. */
  802. static int parseCond(Js *ep, int state, int flags)
  803. {
  804. char *lhs, *rhs;
  805. int tid, operator;
  806. assert(ep);
  807. setString(&ep->result, "");
  808. rhs = lhs = NULL;
  809. operator = 0;
  810. do {
  811. /*
  812. Recurse to handle one side of a conditional. Accumulate the left hand side and the final result in ep->result.
  813. */
  814. state = parse(ep, STATE_RELEXP, flags);
  815. if (state != STATE_RELEXP_DONE) {
  816. state = STATE_ERR;
  817. break;
  818. }
  819. if (operator > 0) {
  820. setString(&rhs, ep->result);
  821. if (evalCond(ep, lhs, operator, rhs) < 0) {
  822. state = STATE_ERR;
  823. break;
  824. }
  825. }
  826. setString(&lhs, ep->result);
  827. tid = jsLexGetToken(ep, state);
  828. if (tid == TOK_LOGICAL) {
  829. operator = (int) *ep->token;
  830. } else if (tid == TOK_RPAREN || tid == TOK_SEMI) {
  831. jsLexPutbackToken(ep, tid, ep->token);
  832. state = STATE_COND_DONE;
  833. break;
  834. } else {
  835. jsLexPutbackToken(ep, tid, ep->token);
  836. }
  837. } while (state == STATE_RELEXP_DONE);
  838. if (lhs) {
  839. wfree(lhs);
  840. }
  841. if (rhs) {
  842. wfree(rhs);
  843. }
  844. return state;
  845. }
  846. /*
  847. Parse expression (leftHandSide operator rightHandSide)
  848. */
  849. static int parseExpr(Js *ep, int state, int flags)
  850. {
  851. char *lhs, *rhs;
  852. int rel, tid;
  853. assert(ep);
  854. setString(&ep->result, "");
  855. rhs = lhs = NULL;
  856. rel = 0;
  857. tid = 0;
  858. do {
  859. /*
  860. This loop will handle an entire expression list. We call parse to evaluate each term which returns the
  861. result in ep->result.
  862. */
  863. if (tid == TOK_LOGICAL) {
  864. if ((state = parse(ep, STATE_RELEXP, flags)) != STATE_RELEXP_DONE) {
  865. state = STATE_ERR;
  866. break;
  867. }
  868. } else {
  869. if ((state = parse(ep, STATE_EXPR, flags)) != STATE_EXPR_DONE) {
  870. state = STATE_ERR;
  871. break;
  872. }
  873. }
  874. if (rel > 0) {
  875. setString(&rhs, ep->result);
  876. if (tid == TOK_LOGICAL) {
  877. if (evalCond(ep, lhs, rel, rhs) < 0) {
  878. state = STATE_ERR;
  879. break;
  880. }
  881. } else {
  882. if (evalExpr(ep, lhs, rel, rhs) < 0) {
  883. state = STATE_ERR;
  884. break;
  885. }
  886. }
  887. }
  888. setString(&lhs, ep->result);
  889. if ((tid = jsLexGetToken(ep, state)) == TOK_EXPR ||
  890. tid == TOK_INC_DEC || tid == TOK_LOGICAL) {
  891. rel = (int) *ep->token;
  892. } else {
  893. jsLexPutbackToken(ep, tid, ep->token);
  894. state = STATE_RELEXP_DONE;
  895. }
  896. } while (state == STATE_EXPR_DONE);
  897. if (rhs) {
  898. wfree(rhs);
  899. }
  900. if (lhs) {
  901. wfree(lhs);
  902. }
  903. return state;
  904. }
  905. /*
  906. Evaluate a condition. Implements &&, ||, !
  907. */
  908. static int evalCond(Js *ep, cchar *lhs, int rel, cchar *rhs)
  909. {
  910. char buf[16];
  911. int l, r, lval;
  912. assert(lhs);
  913. assert(rhs);
  914. assert(rel > 0);
  915. lval = 0;
  916. if (isdigit((uchar) *lhs) && isdigit((uchar) *rhs)) {
  917. l = atoi(lhs);
  918. r = atoi(rhs);
  919. switch (rel) {
  920. case COND_AND:
  921. lval = l && r;
  922. break;
  923. case COND_OR:
  924. lval = l || r;
  925. break;
  926. default:
  927. jsError(ep, "Bad operator %d", rel);
  928. return -1;
  929. }
  930. } else {
  931. if (!isdigit((uchar) *lhs)) {
  932. jsError(ep, "Conditional must be numeric", lhs);
  933. } else {
  934. jsError(ep, "Conditional must be numeric", rhs);
  935. }
  936. }
  937. itosbuf(buf, sizeof(buf), lval, 10);
  938. setString(&ep->result, buf);
  939. return 0;
  940. }
  941. /*
  942. Evaluate an operation
  943. */
  944. static int evalExpr(Js *ep, cchar *lhs, int rel, cchar *rhs)
  945. {
  946. cchar *cp;
  947. char buf[16];
  948. int numeric, l, r, lval;
  949. assert(lhs);
  950. assert(rhs);
  951. assert(rel > 0);
  952. /*
  953. All of the characters in the lhs and rhs must be numeric
  954. */
  955. numeric = 1;
  956. for (cp = lhs; *cp; cp++) {
  957. if (!isdigit((uchar) *cp)) {
  958. numeric = 0;
  959. break;
  960. }
  961. }
  962. if (numeric) {
  963. for (cp = rhs; *cp; cp++) {
  964. if (!isdigit((uchar) *cp)) {
  965. numeric = 0;
  966. break;
  967. }
  968. }
  969. }
  970. if (numeric) {
  971. l = atoi(lhs);
  972. r = atoi(rhs);
  973. switch (rel) {
  974. case EXPR_PLUS:
  975. lval = l + r;
  976. break;
  977. case EXPR_INC:
  978. lval = l + 1;
  979. break;
  980. case EXPR_MINUS:
  981. lval = l - r;
  982. break;
  983. case EXPR_DEC:
  984. lval = l - 1;
  985. break;
  986. case EXPR_MUL:
  987. lval = l * r;
  988. break;
  989. case EXPR_DIV:
  990. if (r != 0) {
  991. lval = l / r;
  992. } else {
  993. lval = 0;
  994. }
  995. break;
  996. case EXPR_MOD:
  997. if (r != 0) {
  998. lval = l % r;
  999. } else {
  1000. lval = 0;
  1001. }
  1002. break;
  1003. case EXPR_LSHIFT:
  1004. lval = l << r;
  1005. break;
  1006. case EXPR_RSHIFT:
  1007. lval = l >> r;
  1008. break;
  1009. case EXPR_EQ:
  1010. lval = l == r;
  1011. break;
  1012. case EXPR_NOTEQ:
  1013. lval = l != r;
  1014. break;
  1015. case EXPR_LESS:
  1016. lval = (l < r) ? 1 : 0;
  1017. break;
  1018. case EXPR_LESSEQ:
  1019. lval = (l <= r) ? 1 : 0;
  1020. break;
  1021. case EXPR_GREATER:
  1022. lval = (l > r) ? 1 : 0;
  1023. break;
  1024. case EXPR_GREATEREQ:
  1025. lval = (l >= r) ? 1 : 0;
  1026. break;
  1027. case EXPR_BOOL_COMP:
  1028. lval = (r == 0) ? 1 : 0;
  1029. break;
  1030. default:
  1031. jsError(ep, "Bad operator %d", rel);
  1032. return -1;
  1033. }
  1034. } else {
  1035. switch (rel) {
  1036. case EXPR_PLUS:
  1037. clearString(&ep->result);
  1038. appendString(&ep->result, lhs);
  1039. appendString(&ep->result, rhs);
  1040. return 0;
  1041. case EXPR_LESS:
  1042. lval = strcmp(lhs, rhs) < 0;
  1043. break;
  1044. case EXPR_LESSEQ:
  1045. lval = strcmp(lhs, rhs) <= 0;
  1046. break;
  1047. case EXPR_GREATER:
  1048. lval = strcmp(lhs, rhs) > 0;
  1049. break;
  1050. case EXPR_GREATEREQ:
  1051. lval = strcmp(lhs, rhs) >= 0;
  1052. break;
  1053. case EXPR_EQ:
  1054. lval = strcmp(lhs, rhs) == 0;
  1055. break;
  1056. case EXPR_NOTEQ:
  1057. lval = strcmp(lhs, rhs) != 0;
  1058. break;
  1059. case EXPR_INC:
  1060. case EXPR_DEC:
  1061. case EXPR_MINUS:
  1062. case EXPR_DIV:
  1063. case EXPR_MOD:
  1064. case EXPR_LSHIFT:
  1065. case EXPR_RSHIFT:
  1066. default:
  1067. jsError(ep, "Bad operator");
  1068. return -1;
  1069. }
  1070. }
  1071. itosbuf(buf, sizeof(buf), lval, 10);
  1072. setString(&ep->result, buf);
  1073. return 0;
  1074. }
  1075. /*
  1076. Evaluate a function
  1077. */
  1078. static int evalFunction(Js *ep)
  1079. {
  1080. WebsKey *sp;
  1081. int (*fn)(int jid, void *handle, int argc, char **argv);
  1082. if ((sp = hashLookup(ep->functions, ep->func->fname)) == NULL) {
  1083. jsError(ep, "Undefined procedure %s", ep->func->fname);
  1084. return -1;
  1085. }
  1086. fn = (int (*)(int, void*, int, char**)) sp->content.value.symbol;
  1087. if (fn == NULL) {
  1088. jsError(ep, "Undefined procedure %s", ep->func->fname);
  1089. return -1;
  1090. }
  1091. return (*fn)(ep->jid, ep->userHandle, ep->func->nArgs, ep->func->args);
  1092. }
  1093. /*
  1094. Output a parse js_error message
  1095. */
  1096. PUBLIC void jsError(Js *ep, cchar* fmt, ...)
  1097. {
  1098. va_list args;
  1099. JsInput *ip;
  1100. char *errbuf, *msgbuf;
  1101. assert(ep);
  1102. assert(fmt);
  1103. ip = ep->input;
  1104. va_start(args, fmt);
  1105. msgbuf = sfmtv(fmt, args);
  1106. va_end(args);
  1107. if (ep && ip) {
  1108. errbuf = sfmt("%s\n At line %d, line => \n\n%s\n", msgbuf, ip->lineNumber, ip->line);
  1109. wfree(ep->error);
  1110. ep->error = errbuf;
  1111. }
  1112. wfree(msgbuf);
  1113. }
  1114. static void clearString(char **ptr)
  1115. {
  1116. assert(ptr);
  1117. if (*ptr) {
  1118. wfree(*ptr);
  1119. }
  1120. *ptr = NULL;
  1121. }
  1122. static void setString(char **ptr, cchar *s)
  1123. {
  1124. assert(ptr);
  1125. if (*ptr) {
  1126. wfree(*ptr);
  1127. }
  1128. *ptr = sclone(s);
  1129. }
  1130. static void appendString(char **ptr, cchar *s)
  1131. {
  1132. ssize len, oldlen, size;
  1133. assert(ptr);
  1134. if (*ptr) {
  1135. len = strlen(s);
  1136. oldlen = strlen(*ptr);
  1137. size = (len + oldlen + 1) * sizeof(char);
  1138. *ptr = wrealloc(*ptr, size);
  1139. strcpy(&(*ptr)[oldlen], s);
  1140. } else {
  1141. *ptr = sclone(s);
  1142. }
  1143. }
  1144. /*
  1145. Define a function
  1146. */
  1147. PUBLIC int jsSetGlobalFunction(int jid, cchar *name, JsProc fn)
  1148. {
  1149. Js *ep;
  1150. if ((ep = jsPtr(jid)) == NULL) {
  1151. return -1;
  1152. }
  1153. return jsSetGlobalFunctionDirect(ep->functions, name, fn);
  1154. }
  1155. /*
  1156. Define a function directly into the function symbol table.
  1157. */
  1158. PUBLIC int jsSetGlobalFunctionDirect(WebsHash functions, cchar *name, JsProc fn)
  1159. {
  1160. if (hashEnter(functions, name, valueSymbol(fn), 0) == NULL) {
  1161. return -1;
  1162. }
  1163. return 0;
  1164. }
  1165. /*
  1166. Remove ("undefine") a function
  1167. */
  1168. PUBLIC int jsRemoveGlobalFunction(int jid, cchar *name)
  1169. {
  1170. Js *ep;
  1171. if ((ep = jsPtr(jid)) == NULL) {
  1172. return -1;
  1173. }
  1174. return hashDelete(ep->functions, name);
  1175. }
  1176. PUBLIC void *jsGetGlobalFunction(int jid, cchar *name)
  1177. {
  1178. Js *ep;
  1179. WebsKey *sp;
  1180. int (*fn)(int jid, void *handle, int argc, char **argv);
  1181. if ((ep = jsPtr(jid)) == NULL) {
  1182. return NULL;
  1183. }
  1184. if ((sp = hashLookup(ep->functions, name)) != NULL) {
  1185. fn = (int (*)(int, void*, int, char**)) sp->content.value.symbol;
  1186. return (void*) fn;
  1187. }
  1188. return NULL;
  1189. }
  1190. /*
  1191. Utility routine to crack Javascript arguments. Return the number of args
  1192. seen. This routine only supports %s and %d type args.
  1193. Typical usage:
  1194. if (jsArgs(argc, argv, "%s %d", &name, &age) < 2) {
  1195. error("Insufficient args");
  1196. return -1;
  1197. }
  1198. */
  1199. PUBLIC int jsArgs(int argc, char **argv, cchar *fmt, ...)
  1200. {
  1201. va_list vargs;
  1202. cchar *cp;
  1203. char **sp;
  1204. int *ip;
  1205. int argn;
  1206. if (argv == NULL) {
  1207. return 0;
  1208. }
  1209. va_start(vargs, fmt);
  1210. for (argn = 0, cp = fmt; cp && *cp && argv[argn]; ) {
  1211. if (*cp++ != '%') {
  1212. continue;
  1213. }
  1214. switch (*cp) {
  1215. case 'd':
  1216. ip = va_arg(vargs, int*);
  1217. *ip = atoi(argv[argn]);
  1218. break;
  1219. case 's':
  1220. sp = va_arg(vargs, char**);
  1221. *sp = argv[argn];
  1222. break;
  1223. default:
  1224. /*
  1225. Unsupported
  1226. */
  1227. assert(0);
  1228. }
  1229. argn++;
  1230. }
  1231. va_end(vargs);
  1232. return argn;
  1233. }
  1234. PUBLIC void jsSetUserHandle(int jid, void* handle)
  1235. {
  1236. Js *ep;
  1237. if ((ep = jsPtr(jid)) == NULL) {
  1238. return;
  1239. }
  1240. ep->userHandle = handle;
  1241. }
  1242. void* jsGetUserHandle(int jid)
  1243. {
  1244. Js *ep;
  1245. if ((ep = jsPtr(jid)) == NULL) {
  1246. return NULL;
  1247. }
  1248. return ep->userHandle;
  1249. }
  1250. PUBLIC int jsGetLineNumber(int jid)
  1251. {
  1252. Js *ep;
  1253. if ((ep = jsPtr(jid)) == NULL) {
  1254. return -1;
  1255. }
  1256. return ep->input->lineNumber;
  1257. }
  1258. PUBLIC void jsSetResult(int jid, cchar *s)
  1259. {
  1260. Js *ep;
  1261. if ((ep = jsPtr(jid)) == NULL) {
  1262. return;
  1263. }
  1264. setString(&ep->result, s);
  1265. }
  1266. PUBLIC cchar *jsGetResult(int jid)
  1267. {
  1268. Js *ep;
  1269. if ((ep = jsPtr(jid)) == NULL) {
  1270. return NULL;
  1271. }
  1272. return ep->result;
  1273. }
  1274. /*
  1275. Set a variable. Note: a variable with a value of NULL means declared but undefined. The value is defined in the
  1276. top-most variable frame.
  1277. */
  1278. PUBLIC void jsSetVar(int jid, cchar *var, cchar *value)
  1279. {
  1280. Js *ep;
  1281. WebsValue v;
  1282. assert(var && *var);
  1283. if ((ep = jsPtr(jid)) == NULL) {
  1284. return;
  1285. }
  1286. if (value == NULL) {
  1287. v = valueString(value, 0);
  1288. } else {
  1289. v = valueString(value, VALUE_ALLOCATE);
  1290. }
  1291. hashEnter(ep->variables[ep->variableMax - 1] - JS_OFFSET, var, v, 0);
  1292. }
  1293. /*
  1294. Set a local variable. Note: a variable with a value of NULL means declared but undefined. The value is defined in
  1295. the top-most variable frame.
  1296. */
  1297. PUBLIC void jsSetLocalVar(int jid, cchar *var, cchar *value)
  1298. {
  1299. Js *ep;
  1300. WebsValue v;
  1301. assert(var && *var);
  1302. if ((ep = jsPtr(jid)) == NULL) {
  1303. return;
  1304. }
  1305. if (value == NULL) {
  1306. v = valueString(value, 0);
  1307. } else {
  1308. v = valueString(value, VALUE_ALLOCATE);
  1309. }
  1310. hashEnter(ep->variables[ep->variableMax - 1] - JS_OFFSET, var, v, 0);
  1311. }
  1312. /*
  1313. Set a global variable. Note: a variable with a value of NULL means declared but undefined. The value is defined in
  1314. the global variable frame.
  1315. */
  1316. PUBLIC void jsSetGlobalVar(int jid, cchar *var, cchar *value)
  1317. {
  1318. Js *ep;
  1319. WebsValue v;
  1320. assert(var && *var);
  1321. if ((ep = jsPtr(jid)) == NULL) {
  1322. return;
  1323. }
  1324. if (value == NULL) {
  1325. v = valueString(value, 0);
  1326. } else {
  1327. v = valueString(value, VALUE_ALLOCATE);
  1328. }
  1329. hashEnter(ep->variables[0] - JS_OFFSET, var, v, 0);
  1330. }
  1331. /*
  1332. Get a variable
  1333. */
  1334. PUBLIC int jsGetVar(int jid, cchar *var, cchar **value)
  1335. {
  1336. Js *ep;
  1337. WebsKey *sp;
  1338. int i;
  1339. assert(var && *var);
  1340. assert(value);
  1341. if ((ep = jsPtr(jid)) == NULL) {
  1342. return -1;
  1343. }
  1344. i = ep->variableMax - 1;
  1345. if ((sp = hashLookup(ep->variables[i] - JS_OFFSET, var)) == NULL) {
  1346. i = 0;
  1347. if ((sp = hashLookup(ep->variables[0] - JS_OFFSET, var)) == NULL) {
  1348. return -1;
  1349. }
  1350. }
  1351. assert(sp->content.type == string);
  1352. *value = sp->content.value.string;
  1353. return i;
  1354. }
  1355. WebsHash jsGetVariableTable(int jid)
  1356. {
  1357. Js *ep;
  1358. if ((ep = jsPtr(jid)) == NULL) {
  1359. return -1;
  1360. }
  1361. return *ep->variables;
  1362. }
  1363. WebsHash jsGetFunctionTable(int jid)
  1364. {
  1365. Js *ep;
  1366. if ((ep = jsPtr(jid)) == NULL) {
  1367. return -1;
  1368. }
  1369. return ep->functions;
  1370. }
  1371. /*
  1372. Free an argument list
  1373. */
  1374. static void freeFunc(JsFun *func)
  1375. {
  1376. int i;
  1377. for (i = func->nArgs - 1; i >= 0; i--) {
  1378. wfree(func->args[i]);
  1379. func->nArgs = wfreeHandle(&func->args, i);
  1380. }
  1381. if (func->fname) {
  1382. wfree(func->fname);
  1383. func->fname = NULL;
  1384. }
  1385. }
  1386. /*
  1387. Get Javascript engine pointer
  1388. */
  1389. static Js *jsPtr(int jid)
  1390. {
  1391. assert(0 <= jid && jid < jsMax);
  1392. if (jid < 0 || jid >= jsMax || jsHandles[jid] == NULL) {
  1393. jsError(NULL, "Bad handle %d", jid);
  1394. return NULL;
  1395. }
  1396. return jsHandles[jid];
  1397. }
  1398. /*
  1399. This function removes any new lines. Used for else cases, etc.
  1400. */
  1401. static void jsRemoveNewlines(Js *ep, int state)
  1402. {
  1403. int tid;
  1404. do {
  1405. tid = jsLexGetToken(ep, state);
  1406. } while (tid == TOK_NEWLINE);
  1407. jsLexPutbackToken(ep, tid, ep->token);
  1408. }
  1409. PUBLIC int jsLexOpen(Js *ep)
  1410. {
  1411. return 0;
  1412. }
  1413. PUBLIC void jsLexClose(Js *ep)
  1414. {
  1415. }
  1416. PUBLIC int jsLexOpenScript(Js *ep, cchar *script)
  1417. {
  1418. JsInput *ip;
  1419. assert(ep);
  1420. assert(script);
  1421. if ((ep->input = walloc(sizeof(JsInput))) == NULL) {
  1422. return -1;
  1423. }
  1424. ip = ep->input;
  1425. memset(ip, 0, sizeof(*ip));
  1426. assert(ip);
  1427. assert(ip->putBackToken == NULL);
  1428. assert(ip->putBackTokenId == 0);
  1429. /*
  1430. Create the parse token buffer and script buffer
  1431. */
  1432. if (bufCreate(&ip->tokbuf, JS_INC, -1) < 0) {
  1433. return -1;
  1434. }
  1435. if (bufCreate(&ip->script, JS_SCRIPT_INC, -1) < 0) {
  1436. return -1;
  1437. }
  1438. /*
  1439. Put the Javascript into a ring queue for easy parsing
  1440. */
  1441. bufPutStr(&ip->script, script);
  1442. ip->lineNumber = 1;
  1443. ip->lineLength = 0;
  1444. ip->lineColumn = 0;
  1445. ip->line = NULL;
  1446. return 0;
  1447. }
  1448. PUBLIC void jsLexCloseScript(Js *ep)
  1449. {
  1450. JsInput *ip;
  1451. assert(ep);
  1452. ip = ep->input;
  1453. assert(ip);
  1454. if (ip->putBackToken) {
  1455. wfree(ip->putBackToken);
  1456. ip->putBackToken = NULL;
  1457. }
  1458. ip->putBackTokenId = 0;
  1459. if (ip->line) {
  1460. wfree(ip->line);
  1461. ip->line = NULL;
  1462. }
  1463. bufFree(&ip->tokbuf);
  1464. bufFree(&ip->script);
  1465. wfree(ip);
  1466. }
  1467. PUBLIC void jsLexSaveInputState(Js *ep, JsInput *state)
  1468. {
  1469. JsInput *ip;
  1470. assert(ep);
  1471. ip = ep->input;
  1472. assert(ip);
  1473. *state = *ip;
  1474. if (ip->putBackToken) {
  1475. state->putBackToken = sclone(ip->putBackToken);
  1476. }
  1477. }
  1478. PUBLIC void jsLexRestoreInputState(Js *ep, JsInput *state)
  1479. {
  1480. JsInput *ip;
  1481. assert(ep);
  1482. ip = ep->input;
  1483. assert(ip);
  1484. ip->tokbuf = state->tokbuf;
  1485. ip->script = state->script;
  1486. ip->putBackTokenId = state->putBackTokenId;
  1487. if (ip->putBackToken) {
  1488. wfree(ip->putBackToken);
  1489. }
  1490. if (state->putBackToken) {
  1491. ip->putBackToken = sclone(state->putBackToken);
  1492. }
  1493. }
  1494. PUBLIC void jsLexFreeInputState(Js *ep, JsInput *state)
  1495. {
  1496. if (state->putBackToken) {
  1497. wfree(state->putBackToken);
  1498. state->putBackToken = NULL;
  1499. }
  1500. }
  1501. PUBLIC int jsLexGetToken(Js *ep, int state)
  1502. {
  1503. ep->tid = getLexicalToken(ep, state);
  1504. return ep->tid;
  1505. }
  1506. static int getLexicalToken(Js *ep, int state)
  1507. {
  1508. WebsBuf *tokq;
  1509. JsInput *ip;
  1510. int done, tid, c, quote, style;
  1511. assert(ep);
  1512. ip = ep->input;
  1513. assert(ip);
  1514. tokq = &ip->tokbuf;
  1515. ep->tid = -1;
  1516. tid = -1;
  1517. ep->token = "";
  1518. bufFlush(tokq);
  1519. if (ip->putBackTokenId > 0) {
  1520. bufPutStr(tokq, ip->putBackToken);
  1521. tid = ip->putBackTokenId;
  1522. ip->putBackTokenId = 0;
  1523. ep->token = (char*) tokq->servp;
  1524. return tid;
  1525. }
  1526. if ((c = inputGetc(ep)) < 0) {
  1527. return TOK_EOF;
  1528. }
  1529. for (done = 0; !done; ) {
  1530. switch (c) {
  1531. case -1:
  1532. return TOK_EOF;
  1533. case ' ':
  1534. case '\t':
  1535. case '\r':
  1536. do {
  1537. if ((c = inputGetc(ep)) < 0)
  1538. break;
  1539. } while (c == ' ' || c == '\t' || c == '\r');
  1540. break;
  1541. case '\n':
  1542. return TOK_NEWLINE;
  1543. case '(':
  1544. tokenAddChar(ep, c);
  1545. return TOK_LPAREN;
  1546. case ')':
  1547. tokenAddChar(ep, c);
  1548. return TOK_RPAREN;
  1549. case '{':
  1550. tokenAddChar(ep, c);
  1551. return TOK_LBRACE;
  1552. case '}':
  1553. tokenAddChar(ep, c);
  1554. return TOK_RBRACE;
  1555. case '+':
  1556. if ((c = inputGetc(ep)) < 0) {
  1557. jsError(ep, "Syntax Error");
  1558. return TOK_ERR;
  1559. }
  1560. if (c != '+' ) {
  1561. inputPutback(ep, c);
  1562. tokenAddChar(ep, EXPR_PLUS);
  1563. return TOK_EXPR;
  1564. }
  1565. tokenAddChar(ep, EXPR_INC);
  1566. return TOK_INC_DEC;
  1567. case '-':
  1568. if ((c = inputGetc(ep)) < 0) {
  1569. jsError(ep, "Syntax Error");
  1570. return TOK_ERR;
  1571. }
  1572. if (c != '-' ) {
  1573. inputPutback(ep, c);
  1574. tokenAddChar(ep, EXPR_MINUS);
  1575. return TOK_EXPR;
  1576. }
  1577. tokenAddChar(ep, EXPR_DEC);
  1578. return TOK_INC_DEC;
  1579. case '*':
  1580. tokenAddChar(ep, EXPR_MUL);
  1581. return TOK_EXPR;
  1582. case '%':
  1583. tokenAddChar(ep, EXPR_MOD);
  1584. return TOK_EXPR;
  1585. case '/':
  1586. /*
  1587. Handle the division operator and comments
  1588. */
  1589. if ((c = inputGetc(ep)) < 0) {
  1590. jsError(ep, "Syntax Error");
  1591. return TOK_ERR;
  1592. }
  1593. if (c != '*' && c != '/') {
  1594. inputPutback(ep, c);
  1595. tokenAddChar(ep, EXPR_DIV);
  1596. return TOK_EXPR;
  1597. }
  1598. style = c;
  1599. /*
  1600. Eat comments. Both C and C++ comment styles are supported.
  1601. */
  1602. while (1) {
  1603. if ((c = inputGetc(ep)) < 0) {
  1604. jsError(ep, "Syntax Error");
  1605. return TOK_ERR;
  1606. }
  1607. if (c == '\n' && style == '/') {
  1608. break;
  1609. } else if (c == '*') {
  1610. c = inputGetc(ep);
  1611. if (style == '/') {
  1612. if (c == '\n') {
  1613. break;
  1614. }
  1615. } else {
  1616. if (c == '/') {
  1617. break;
  1618. }
  1619. }
  1620. }
  1621. }
  1622. /*
  1623. Continue looking for a token, so get the next character
  1624. */
  1625. if ((c = inputGetc(ep)) < 0) {
  1626. return TOK_EOF;
  1627. }
  1628. break;
  1629. case '<': /* < and <= */
  1630. if ((c = inputGetc(ep)) < 0) {
  1631. jsError(ep, "Syntax Error");
  1632. return TOK_ERR;
  1633. }
  1634. if (c == '<') {
  1635. tokenAddChar(ep, EXPR_LSHIFT);
  1636. return TOK_EXPR;
  1637. } else if (c == '=') {
  1638. tokenAddChar(ep, EXPR_LESSEQ);
  1639. return TOK_EXPR;
  1640. }
  1641. tokenAddChar(ep, EXPR_LESS);
  1642. inputPutback(ep, c);
  1643. return TOK_EXPR;
  1644. case '>': /* > and >= */
  1645. if ((c = inputGetc(ep)) < 0) {
  1646. jsError(ep, "Syntax Error");
  1647. return TOK_ERR;
  1648. }
  1649. if (c == '>') {
  1650. tokenAddChar(ep, EXPR_RSHIFT);
  1651. return TOK_EXPR;
  1652. } else if (c == '=') {
  1653. tokenAddChar(ep, EXPR_GREATEREQ);
  1654. return TOK_EXPR;
  1655. }
  1656. tokenAddChar(ep, EXPR_GREATER);
  1657. inputPutback(ep, c);
  1658. return TOK_EXPR;
  1659. case '=': /* "==" */
  1660. if ((c = inputGetc(ep)) < 0) {
  1661. jsError(ep, "Syntax Error");
  1662. return TOK_ERR;
  1663. }
  1664. if (c == '=') {
  1665. tokenAddChar(ep, EXPR_EQ);
  1666. return TOK_EXPR;
  1667. }
  1668. inputPutback(ep, c);
  1669. return TOK_ASSIGNMENT;
  1670. case '!': /* "!=" or "!"*/
  1671. if ((c = inputGetc(ep)) < 0) {
  1672. jsError(ep, "Syntax Error");
  1673. return TOK_ERR;
  1674. }
  1675. if (c == '=') {
  1676. tokenAddChar(ep, EXPR_NOTEQ);
  1677. return TOK_EXPR;
  1678. }
  1679. inputPutback(ep, c);
  1680. tokenAddChar(ep, EXPR_BOOL_COMP);
  1681. return TOK_EXPR;
  1682. case ';':
  1683. tokenAddChar(ep, c);
  1684. return TOK_SEMI;
  1685. case ',':
  1686. tokenAddChar(ep, c);
  1687. return TOK_COMMA;
  1688. case '|': /* "||" */
  1689. if ((c = inputGetc(ep)) < 0 || c != '|') {
  1690. jsError(ep, "Syntax Error");
  1691. return TOK_ERR;
  1692. }
  1693. tokenAddChar(ep, COND_OR);
  1694. return TOK_LOGICAL;
  1695. case '&': /* "&&" */
  1696. if ((c = inputGetc(ep)) < 0 || c != '&') {
  1697. jsError(ep, "Syntax Error");
  1698. return TOK_ERR;
  1699. }
  1700. tokenAddChar(ep, COND_AND);
  1701. return TOK_LOGICAL;
  1702. case '\"': /* String quote */
  1703. case '\'':
  1704. quote = c;
  1705. if ((c = inputGetc(ep)) < 0) {
  1706. jsError(ep, "Syntax Error");
  1707. return TOK_ERR;
  1708. }
  1709. while (c != quote) {
  1710. /*
  1711. check for escape sequence characters
  1712. */
  1713. if (c == '\\') {
  1714. c = inputGetc(ep);
  1715. if (isdigit((uchar) c)) {
  1716. /*
  1717. octal support, \101 maps to 65 = 'A'. put first char back so converter will work properly.
  1718. */
  1719. inputPutback(ep, c);
  1720. c = charConvert(ep, OCTAL, 3);
  1721. } else {
  1722. switch (c) {
  1723. case 'n':
  1724. c = '\n'; break;
  1725. case 'b':
  1726. c = '\b'; break;
  1727. case 'f':
  1728. c = '\f'; break;
  1729. case 'r':
  1730. c = '\r'; break;
  1731. case 't':
  1732. c = '\t'; break;
  1733. case 'x':
  1734. /*
  1735. hex support, \x41 maps to 65 = 'A'
  1736. */
  1737. c = charConvert(ep, HEX, 2);
  1738. break;
  1739. case 'u':
  1740. /*
  1741. unicode support, \x0401 maps to 65 = 'A'
  1742. */
  1743. c = charConvert(ep, HEX, 2);
  1744. c = c*16 + charConvert(ep, HEX, 2);
  1745. break;
  1746. case '\'':
  1747. case '\"':
  1748. case '\\':
  1749. break;
  1750. default:
  1751. jsError(ep, "Invalid Escape Sequence");
  1752. return TOK_ERR;
  1753. }
  1754. }
  1755. if (tokenAddChar(ep, c) < 0) {
  1756. return TOK_ERR;
  1757. }
  1758. } else {
  1759. if (tokenAddChar(ep, c) < 0) {
  1760. return TOK_ERR;
  1761. }
  1762. }
  1763. if ((c = inputGetc(ep)) < 0) {
  1764. jsError(ep, "Unmatched Quote");
  1765. return TOK_ERR;
  1766. }
  1767. }
  1768. return TOK_LITERAL;
  1769. case '0': case '1': case '2': case '3': case '4':
  1770. case '5': case '6': case '7': case '8': case '9':
  1771. do {
  1772. if (tokenAddChar(ep, c) < 0) {
  1773. return TOK_ERR;
  1774. }
  1775. if ((c = inputGetc(ep)) < 0)
  1776. break;
  1777. } while (isdigit((uchar) c));
  1778. inputPutback(ep, c);
  1779. return TOK_LITERAL;
  1780. default:
  1781. /*
  1782. Identifiers or a function names
  1783. */
  1784. while (1) {
  1785. if (c == '\\') {
  1786. /*
  1787. just ignore any \ characters.
  1788. */
  1789. } else if (tokenAddChar(ep, c) < 0) {
  1790. break;
  1791. }
  1792. if ((c = inputGetc(ep)) < 0) {
  1793. break;
  1794. }
  1795. if (!isalnum((uchar) c) && c != '$' && c != '_' && c != '\\') {
  1796. break;
  1797. }
  1798. }
  1799. if (! isalpha((uchar) *tokq->servp) && *tokq->servp != '$' && *tokq->servp != '_') {
  1800. jsError(ep, "Invalid identifier %s", tokq->servp);
  1801. return TOK_ERR;
  1802. }
  1803. /*
  1804. Check for reserved words (only "if", "else", "var", "for" and "return" at the moment)
  1805. */
  1806. if (state == STATE_STMT) {
  1807. if (strcmp(ep->token, "if") == 0) {
  1808. return TOK_IF;
  1809. } else if (strcmp(ep->token, "else") == 0) {
  1810. return TOK_ELSE;
  1811. } else if (strcmp(ep->token, "var") == 0) {
  1812. return TOK_VAR;
  1813. } else if (strcmp(ep->token, "for") == 0) {
  1814. return TOK_FOR;
  1815. } else if (strcmp(ep->token, "return") == 0) {
  1816. if ((c == ';') || (c == '(')) {
  1817. inputPutback(ep, c);
  1818. }
  1819. return TOK_RETURN;
  1820. }
  1821. }
  1822. /*
  1823. Skip white space after token to find out whether this is a function or not.
  1824. */
  1825. while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
  1826. if ((c = inputGetc(ep)) < 0)
  1827. break;
  1828. }
  1829. tid = (c == '(') ? TOK_FUNCTION : TOK_ID;
  1830. done++;
  1831. }
  1832. }
  1833. /*
  1834. Putback the last extra character for next time
  1835. */
  1836. inputPutback(ep, c);
  1837. return tid;
  1838. }
  1839. PUBLIC void jsLexPutbackToken(Js *ep, int tid, cchar *string)
  1840. {
  1841. JsInput *ip;
  1842. assert(ep);
  1843. ip = ep->input;
  1844. assert(ip);
  1845. if (ip->putBackToken) {
  1846. wfree(ip->putBackToken);
  1847. }
  1848. ip->putBackTokenId = tid;
  1849. ip->putBackToken = sclone(string);
  1850. }
  1851. static int tokenAddChar(Js *ep, int c)
  1852. {
  1853. JsInput *ip;
  1854. assert(ep);
  1855. ip = ep->input;
  1856. assert(ip);
  1857. if (bufPutc(&ip->tokbuf, (char) c) < 0) {
  1858. jsError(ep, "Token too big");
  1859. return -1;
  1860. }
  1861. * ((char*) ip->tokbuf.endp) = '\0';
  1862. ep->token = (char*) ip->tokbuf.servp;
  1863. return 0;
  1864. }
  1865. static int inputGetc(Js *ep)
  1866. {
  1867. JsInput *ip;
  1868. ssize len;
  1869. int c;
  1870. assert(ep);
  1871. ip = ep->input;
  1872. if ((len = bufLen(&ip->script)) == 0) {
  1873. return -1;
  1874. }
  1875. c = bufGetc(&ip->script);
  1876. if (c == '\n') {
  1877. ip->lineNumber++;
  1878. ip->lineColumn = 0;
  1879. } else {
  1880. if ((ip->lineColumn + 2) >= ip->lineLength) {
  1881. ip->lineLength += JS_INC;
  1882. ip->line = wrealloc(ip->line, ip->lineLength * sizeof(char));
  1883. }
  1884. ip->line[ip->lineColumn++] = c;
  1885. ip->line[ip->lineColumn] = '\0';
  1886. }
  1887. return c;
  1888. }
  1889. static void inputPutback(Js *ep, int c)
  1890. {
  1891. JsInput *ip;
  1892. assert(ep);
  1893. ip = ep->input;
  1894. bufInsertc(&ip->script, (char) c);
  1895. /* Fix by Fred Sauer, 2002/12/23 */
  1896. if (ip->lineColumn > 0) {
  1897. ip->lineColumn-- ;
  1898. }
  1899. ip->line[ip->lineColumn] = '\0';
  1900. }
  1901. /*
  1902. Convert a hex or octal character back to binary, return original char if not a hex digit
  1903. */
  1904. static int charConvert(Js *ep, int base, int maxDig)
  1905. {
  1906. int i, c, lval, convChar;
  1907. lval = 0;
  1908. for (i = 0; i < maxDig; i++) {
  1909. if ((c = inputGetc(ep)) < 0) {
  1910. break;
  1911. }
  1912. /*
  1913. Initialize to out of range value
  1914. */
  1915. convChar = base;
  1916. if (isdigit((uchar) c)) {
  1917. convChar = c - '0';
  1918. } else if (c >= 'a' && c <= 'f') {
  1919. convChar = c - 'a' + 10;
  1920. } else if (c >= 'A' && c <= 'F') {
  1921. convChar = c - 'A' + 10;
  1922. }
  1923. /*
  1924. if unexpected character then return it to buffer.
  1925. */
  1926. if (convChar >= base) {
  1927. inputPutback(ep, c);
  1928. break;
  1929. }
  1930. lval = (lval * base) + convChar;
  1931. }
  1932. return lval;
  1933. }
  1934. #endif /* ME_GOAHEAD_JAVASCRIPT */
  1935. /*
  1936. Copyright (c) Embedthis Software. All Rights Reserved.
  1937. This software is distributed under commercial and open source licenses.
  1938. You may use the Embedthis GoAhead open source license or you may acquire
  1939. a commercial license from Embedthis Software. You agree to be fully bound
  1940. by the terms of either license. Consult the LICENSE.md distributed with
  1941. this software for full details and other copyrights.
  1942. */