espruino.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/stat.h>
  5. #include <signal.h>
  6. #include <dirent.h> // for readdir
  7. #include "jslex.h"
  8. #include "jsvar.h"
  9. #include "jsparse.h"
  10. #include "jswrap_json.h"
  11. #include "jsinteractive.h"
  12. #include "jshardware.h"
  13. #include <finsh.h>
  14. #define TEST_DIR "tests/"
  15. bool isRunning = true;
  16. void nativeQuit(JsVarRef var) {
  17. NOT_USED(var);
  18. isRunning = false;
  19. }
  20. void nativeInterrupt(JsVarRef var) {
  21. NOT_USED(var);
  22. jspSetInterrupted(true);
  23. }
  24. const char *read_file(const char *filename) {
  25. struct stat results;
  26. if (!stat(filename, &results) == 0) {
  27. printf("Cannot stat file! '%s'\r\n", filename);
  28. return 0;
  29. }
  30. int size = (int)results.st_size;
  31. FILE *file = fopen( filename, "rb" );
  32. /* if we open as text, the number of bytes read may be > the size we read */
  33. if( !file ) {
  34. printf("Unable to open file! '%s'\r\n", filename);
  35. return 0;
  36. }
  37. char *buffer = malloc(size+1);
  38. size_t actualRead = fread(buffer,1,size,file);
  39. buffer[actualRead]=0;
  40. buffer[size]=0;
  41. fclose(file);
  42. return buffer;
  43. }
  44. bool run_test(const char *filename) {
  45. printf("----------------------------------\r\n");
  46. printf("----------------------------- TEST %s \r\n", filename);
  47. char *buffer = (char *)read_file(filename);
  48. if (!buffer) return (false);
  49. jshInit();
  50. jsiInit(false /* do not autoload!!! */);
  51. jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
  52. jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt);
  53. jsvUnLock(jspEvaluate(jsiGetParser(), buffer ));
  54. isRunning = true;
  55. while (isRunning && jsiHasTimers()) jsiLoop();
  56. JsVar *result = jsvObjectGetChild(jsiGetParser()->root, "result", 0/*no create*/);
  57. bool pass = jsvGetBool(result);
  58. jsvUnLock(result);
  59. if (pass)
  60. printf("----------------------------- PASS %s\r\n", filename);
  61. else {
  62. printf("----------------------------------\r\n");
  63. printf("----------------------------- FAIL %s <-------\r\n", filename);
  64. jsvTrace(jsvGetRef(jsiGetParser()->root), 0);
  65. printf("----------------------------- FAIL %s <-------\r\n", filename);
  66. printf("----------------------------------\r\n");
  67. }
  68. printf("BEFORE: %d Memory Records Used\r\n", jsvGetMemoryUsage());
  69. // jsvTrace(jsiGetParser()->root, 0);
  70. jsiKill();
  71. printf("AFTER: %d Memory Records Used\r\n", jsvGetMemoryUsage());
  72. jsvGarbageCollect();
  73. printf("AFTER GC: %d Memory Records Used (should be 0!)\r\n", jsvGetMemoryUsage());
  74. jsvShowAllocated();
  75. jshKill();
  76. //jsvDottyOutput();
  77. printf("\r\n");
  78. free(buffer);
  79. return pass;
  80. }
  81. bool run_all_tests() {
  82. int count = 0;
  83. int passed = 0;
  84. char *fails = malloc(1);
  85. fails[0] = 0;
  86. DIR *dir = opendir(TEST_DIR);
  87. if(dir) {
  88. struct dirent *pDir=NULL;
  89. while((pDir = readdir(dir)) != NULL) {
  90. char *fn = (*pDir).d_name;
  91. int l = strlen(fn);
  92. if (l>3 && fn[l-3]=='.' && fn[l-2]=='j' && fn[l-1]=='s') {
  93. char *full_fn = malloc(1+l+strlen(TEST_DIR));
  94. strcpy(full_fn, TEST_DIR);
  95. strcat(full_fn, fn);
  96. if (run_test(full_fn)) {
  97. passed++;
  98. } else {
  99. char *t = malloc(strlen(fails)+3+strlen(full_fn));
  100. strcpy(t, fails);
  101. strcat(t,full_fn);
  102. strcat(t,"\r\n");
  103. free(fails);
  104. fails =t;
  105. }
  106. count++;
  107. }
  108. }
  109. closedir(dir);
  110. } else {
  111. printf(TEST_DIR" directory not found");
  112. }
  113. if (count==0) printf("No tests found in "TEST_DIR"test*.js!\r\n");
  114. printf("--------------------------------------------------\r\n");
  115. printf(" %d of %d tests passed\r\n", passed, count);
  116. if (passed!=count) {
  117. printf("FAILS:\r\n%s", fails);
  118. }
  119. printf("--------------------------------------------------\r\n");
  120. free(fails);
  121. return passed == count;
  122. }
  123. bool run_memory_test(const char *fn, int vars) {
  124. int i;
  125. int min = 20;
  126. int max = 100;
  127. if (vars>0) {
  128. min = vars;
  129. max = vars+1;
  130. }
  131. for (i=min;i<max;i++) {
  132. jsvSetMaxVarsUsed(i);
  133. printf("----------------------------------------------------- MEMORY TEST WITH %d VARS\n", i);
  134. if (!run_test(fn))
  135. return false;
  136. }
  137. return true;
  138. }
  139. bool run_memory_tests(int vars) {
  140. int test_num = 1;
  141. int count = 0;
  142. int passed = 0;
  143. while (test_num<1000) {
  144. char fn[32];
  145. sprintf(fn, TEST_DIR"test%03d.js", test_num);
  146. // check if the file exists - if not, assume we're at the end of our tests
  147. FILE *f = fopen(fn,"r");
  148. if (!f) break;
  149. fclose(f);
  150. run_memory_test(fn, vars);
  151. test_num++;
  152. }
  153. if (count==0) printf("No tests found in "TEST_DIR"test*.js!\n");
  154. return true;
  155. }
  156. void show_help() {
  157. printf("Usage:\n");
  158. printf(" ./espruino : JavaScript immdeiate mode (REPL)\n");
  159. printf(" ./espruino script.js : Load and run script.js\n");
  160. printf(" ./espruino -e \"print('Hello World')\" : Print 'Hello World'\n");
  161. printf("\n");
  162. printf("Options:\n");
  163. printf(" -h, --help Print this help screen\n");
  164. printf(" -e, --eval script Evaluate the JavaScript supplied on the command-line\n");
  165. printf(" --test-all Run all tests (in 'tests' directory)\n");
  166. printf(" --test test.js Run the supplied test\n");
  167. printf(" --test-mem-all Run all Exhaustive Memory crash tests\n");
  168. printf(" --test-mem test.js Run the supplied Exhaustive Memory crash test\n");
  169. printf(" --test-mem-n test.js # Run the supplied Exhaustive Memory crash test with # vars\n");
  170. }
  171. #define die(txt) \
  172. do{ \
  173. printf("%s", txt); \
  174. return (1); \
  175. } while(0)
  176. int espruino(int argc, char **argv) {
  177. int i;
  178. for (i=1;i<argc;i++) {
  179. if (argv[i][0]=='-') {
  180. // option
  181. char *a = argv[i];
  182. if (!strcmp(a,"-h") || !strcmp(a,"--help")) {
  183. show_help();
  184. return (1);
  185. } else if (!strcmp(a,"-e") || !strcmp(a,"--eval")) {
  186. if (i+1>=argc) die("Expecting an extra argument\n");
  187. jshInit();
  188. jsiInit(true);
  189. jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
  190. jsvUnLock(jspEvaluate(jsiGetParser(), argv[i+1]));
  191. isRunning = true;
  192. //while (isRunning && jsiHasTimers()) jsiLoop();
  193. jsiKill();
  194. jshKill();
  195. return (0);
  196. } else if (!strcmp(a,"--test")) {
  197. if (i+1>=argc) die("Expecting an extra argument\n");
  198. bool ok = run_test(argv[i+1]);
  199. return (ok ? 0 : 1);
  200. } else if (!strcmp(a,"--test-all")) {
  201. bool ok = run_all_tests();
  202. return (ok ? 0 : 1);
  203. } else if (!strcmp(a,"--test-mem-all")) {
  204. bool ok = run_memory_tests(0);
  205. return (ok ? 0 : 1);
  206. } else if (!strcmp(a,"--test-mem")) {
  207. if (i+1>=argc) die("Expecting an extra argument\n");
  208. bool ok = run_memory_test(argv[i+1], 0);
  209. return (ok ? 0 : 1);
  210. } else if (!strcmp(a,"--test-mem-n")) {
  211. if (i+2>=argc) die("Expecting an extra 2 arguments\n");
  212. bool ok = run_memory_test(argv[i+1], atoi(argv[i+2]));
  213. return (ok ? 0 : 1);
  214. } else {
  215. printf("Unknown Argument %s\n", a);
  216. show_help();
  217. return -1;
  218. }
  219. }
  220. }
  221. if (argc==1) {
  222. printf("Interactive mode.\n");
  223. } else if (argc==2) {
  224. // single file - just run it
  225. char *buffer = (char *)read_file(argv[1]);
  226. if (!buffer) return (1);
  227. // check for '#' as the first char, and if so, skip the first line
  228. char *cmd = buffer;
  229. if (cmd[0]=='#') {
  230. while (cmd[0] && cmd[0]!='\n') cmd++;
  231. if (cmd[0]=='\n') cmd++;
  232. }
  233. jshInit();
  234. jsiInit(false /* do not autoload!!! */);
  235. jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
  236. jsvUnLock(jspEvaluate(jsiGetParser(), cmd ));
  237. free(buffer);
  238. //isRunning = true;
  239. //while (isRunning && jsiHasTimers()) jsiLoop();
  240. jsiKill();
  241. jshKill();
  242. return -1;
  243. } else {
  244. printf("Unknown arguments!\n");
  245. show_help();
  246. return -1;
  247. }
  248. printf("Size of JsVar is now %d bytes\n", (int)sizeof(JsVar));
  249. printf("Size of JsVarRef is now %d bytes\n", (int)sizeof(JsVarRef));
  250. jshInit();
  251. jsiInit(true);
  252. jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
  253. jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt);
  254. while (isRunning) {
  255. jsiLoop();
  256. }
  257. jsiConsolePrint("\n");
  258. jsiKill();
  259. jsvShowAllocated();
  260. jshKill();
  261. return 0;
  262. }
  263. MSH_CMD_EXPORT(espruino, JavaScript Interpreter)