testparser.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #! /usr/bin/env node
  2. global.DIGITS_OVERRIDE_FOR_TESTING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
  3. var parseJS = require("../lib/parse-js");
  4. var sys = require("util");
  5. // write debug in a very straightforward manner
  6. var debug = function(){
  7. sys.log(Array.prototype.slice.call(arguments).join(', '));
  8. };
  9. var testsPassed = true;
  10. ParserTestSuite(function(i, input, desc){
  11. try {
  12. parseJS.parse(input);
  13. debug("ok " + i + ": " + desc);
  14. } catch(e){
  15. debug("FAIL " + i + " " + desc + " (" + e + ")");
  16. testsPassed = false;
  17. }
  18. });
  19. process.exit(testsPassed ? 0 : 1);
  20. function ParserTestSuite(callback){
  21. var inps = [
  22. ["var abc;", "Regular variable statement w/o assignment"],
  23. ["var abc = 5;", "Regular variable statement with assignment"],
  24. ["/* */;", "Multiline comment"],
  25. ['/** **/;', 'Double star multiline comment'],
  26. ["var f = function(){;};", "Function expression in var assignment"],
  27. ['hi; // moo\n;', 'single line comment'],
  28. ['var varwithfunction;', 'Dont match keywords as substrings'], // difference between `var withsomevar` and `"str"` (local search and lits)
  29. ['a + b;', 'addition'],
  30. ["'a';", 'single string literal'],
  31. ["'a\\n';", 'single string literal with escaped return'],
  32. ['"a";', 'double string literal'],
  33. ['"a\\n";', 'double string literal with escaped return'],
  34. ['"var";', 'string is a keyword'],
  35. ['"variable";', 'string starts with a keyword'],
  36. ['"somevariable";', 'string contains a keyword'],
  37. ['"somevar";', 'string ends with a keyword'],
  38. ['500;', 'int literal'],
  39. ['500.;', 'float literal w/o decimals'],
  40. ['500.432;', 'float literal with decimals'],
  41. ['.432432;', 'float literal w/o int'],
  42. ['(a,b,c);', 'parens and comma'],
  43. ['[1,2,abc];', 'array literal'],
  44. ['var o = {a:1};', 'object literal unquoted key'],
  45. ['var o = {"b":2};', 'object literal quoted key'], // opening curly may not be at the start of a statement...
  46. ['var o = {c:c};', 'object literal keyname is identifier'],
  47. ['var o = {a:1,"b":2,c:c};', 'object literal combinations'],
  48. ['var x;\nvar y;', 'two lines'],
  49. ['var x;\nfunction n(){; }', 'function def'],
  50. ['var x;\nfunction n(abc){; }', 'function def with arg'],
  51. ['var x;\nfunction n(abc, def){ ;}', 'function def with args'],
  52. ['function n(){ "hello"; }', 'function def with body'],
  53. ['/a/;', 'regex literal'],
  54. ['/a/b;', 'regex literal with flag'],
  55. ['/a/ / /b/;', 'regex div regex'],
  56. ['a/b/c;', 'triple division looks like regex'],
  57. ['+function(){/regex/;};', 'regex at start of function body'],
  58. // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=86
  59. // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=430
  60. // first tests for the lexer, should also parse as program (when you append a semi)
  61. // comments
  62. ['//foo!@#^&$1234\nbar;', 'single line comment'],
  63. ['/* abcd!@#@$* { } && null*/;', 'single line multi line comment'],
  64. ['/*foo\nbar*/;','multi line comment'],
  65. ['/*x*x*/;','multi line comment with *'],
  66. ['/**/;','empty comment'],
  67. // identifiers
  68. ["x;",'1 identifier'],
  69. ["_x;",'2 identifier'],
  70. ["xyz;",'3 identifier'],
  71. ["$x;",'4 identifier'],
  72. ["x$;",'5 identifier'],
  73. ["_;",'6 identifier'],
  74. ["x5;",'7 identifier'],
  75. ["x_y;",'8 identifier'],
  76. ["x+5;",'9 identifier'],
  77. ["xyz123;",'10 identifier'],
  78. ["x1y1z1;",'11 identifier'],
  79. ["foo\\u00D8bar;",'12 identifier unicode escape'],
  80. //["foo�bar;",'13 identifier unicode embedded (might fail)'],
  81. // numbers
  82. ["5;", '1 number'],
  83. ["5.5;", '2 number'],
  84. ["0;", '3 number'],
  85. ["0.0;", '4 number'],
  86. ["0.001;", '5 number'],
  87. ["1.e2;", '6 number'],
  88. ["1.e-2;", '7 number'],
  89. ["1.E2;", '8 number'],
  90. ["1.E-2;", '9 number'],
  91. [".5;", '10 number'],
  92. [".5e3;", '11 number'],
  93. [".5e-3;", '12 number'],
  94. ["0.5e3;", '13 number'],
  95. ["55;", '14 number'],
  96. ["123;", '15 number'],
  97. ["55.55;", '16 number'],
  98. ["55.55e10;", '17 number'],
  99. ["123.456;", '18 number'],
  100. ["1+e;", '20 number'],
  101. ["0x01;", '22 number'],
  102. ["0XCAFE;", '23 number'],
  103. ["0x12345678;", '24 number'],
  104. ["0x1234ABCD;", '25 number'],
  105. ["0x0001;", '26 number'],
  106. // strings
  107. ["\"foo\";", '1 string'],
  108. ["\'foo\';", '2 string'],
  109. ["\"x\";", '3 string'],
  110. ["\'\';", '4 string'],
  111. ["\"foo\\tbar\";", '5 string'],
  112. ["\"!@#$%^&*()_+{}[]\";", '6 string'],
  113. ["\"/*test*/\";", '7 string'],
  114. ["\"//test\";", '8 string'],
  115. ["\"\\\\\";", '9 string'],
  116. ["\"\\u0001\";", '10 string'],
  117. ["\"\\uFEFF\";", '11 string'],
  118. ["\"\\u10002\";", '12 string'],
  119. ["\"\\x55\";", '13 string'],
  120. ["\"\\x55a\";", '14 string'],
  121. ["\"a\\\\nb\";", '15 string'],
  122. ['";"', '16 string: semi in a string'],
  123. ['"a\\\nb";', '17 string: line terminator escape'],
  124. // literals
  125. ["null;", "null"],
  126. ["true;", "true"],
  127. ["false;", "false"],
  128. // regex
  129. ["/a/;", "1 regex"],
  130. ["/abc/;", "2 regex"],
  131. ["/abc[a-z]*def/g;", "3 regex"],
  132. ["/\\b/;", "4 regex"],
  133. ["/[a-zA-Z]/;", "5 regex"],
  134. // program tests (for as far as they havent been covered above)
  135. // regexp
  136. ["/foo(.*)/g;", "another regexp"],
  137. // arrays
  138. ["[];", "1 array"],
  139. ["[ ];", "2 array"],
  140. ["[1];", "3 array"],
  141. ["[1,2];", "4 array"],
  142. ["[1,2,,];", "5 array"],
  143. ["[1,2,3];", "6 array"],
  144. ["[1,2,3,,,];", "7 array"],
  145. // objects
  146. ["{};", "1 object"],
  147. ["({x:5});", "2 object"],
  148. ["({x:5,y:6});", "3 object"],
  149. ["({x:5,});", "4 object"],
  150. ["({if:5});", "5 object"],
  151. ["({ get x() {42;} });", "6 object"],
  152. ["({ set y(a) {1;} });", "7 object"],
  153. // member expression
  154. ["o.m;", "1 member expression"],
  155. ["o['m'];", "2 member expression"],
  156. ["o['n']['m'];", "3 member expression"],
  157. ["o.n.m;", "4 member expression"],
  158. ["o.if;", "5 member expression"],
  159. // call and invoke expressions
  160. ["f();", "1 call/invoke expression"],
  161. ["f(x);", "2 call/invoke expression"],
  162. ["f(x,y);", "3 call/invoke expression"],
  163. ["o.m();", "4 call/invoke expression"],
  164. ["o['m'];", "5 call/invoke expression"],
  165. ["o.m(x);", "6 call/invoke expression"],
  166. ["o['m'](x);", "7 call/invoke expression"],
  167. ["o.m(x,y);", "8 call/invoke expression"],
  168. ["o['m'](x,y);", "9 call/invoke expression"],
  169. ["f(x)(y);", "10 call/invoke expression"],
  170. ["f().x;", "11 call/invoke expression"],
  171. // eval
  172. ["eval('x');", "1 eval"],
  173. ["(eval)('x');", "2 eval"],
  174. ["(1,eval)('x');", "3 eval"],
  175. ["eval(x,y);", "4 eval"],
  176. // new expression
  177. ["new f();", "1 new expression"],
  178. ["new o;", "2 new expression"],
  179. ["new o.m;", "3 new expression"],
  180. ["new o.m(x);", "4 new expression"],
  181. ["new o.m(x,y);", "5 new expression"],
  182. // prefix/postfix
  183. ["++x;", "1 pre/postfix"],
  184. ["x++;", "2 pre/postfix"],
  185. ["--x;", "3 pre/postfix"],
  186. ["x--;", "4 pre/postfix"],
  187. ["x ++;", "5 pre/postfix"],
  188. ["x /* comment */ ++;", "6 pre/postfix"],
  189. ["++ /* comment */ x;", "7 pre/postfix"],
  190. // unary operators
  191. ["delete x;", "1 unary operator"],
  192. ["void x;", "2 unary operator"],
  193. ["+ x;", "3 unary operator"],
  194. ["-x;", "4 unary operator"],
  195. ["~x;", "5 unary operator"],
  196. ["!x;", "6 unary operator"],
  197. // meh
  198. ["new Date++;", "new date ++"],
  199. ["+x++;", " + x ++"],
  200. // expression expressions
  201. ["1 * 2;", "1 expression expressions"],
  202. ["1 / 2;", "2 expression expressions"],
  203. ["1 % 2;", "3 expression expressions"],
  204. ["1 + 2;", "4 expression expressions"],
  205. ["1 - 2;", "5 expression expressions"],
  206. ["1 << 2;", "6 expression expressions"],
  207. ["1 >>> 2;", "7 expression expressions"],
  208. ["1 >> 2;", "8 expression expressions"],
  209. ["1 * 2 + 3;", "9 expression expressions"],
  210. ["(1+2)*3;", "10 expression expressions"],
  211. ["1*(2+3);", "11 expression expressions"],
  212. ["x<y;", "12 expression expressions"],
  213. ["x>y;", "13 expression expressions"],
  214. ["x<=y;", "14 expression expressions"],
  215. ["x>=y;", "15 expression expressions"],
  216. ["x instanceof y;", "16 expression expressions"],
  217. ["x in y;", "17 expression expressions"],
  218. ["x&y;", "18 expression expressions"],
  219. ["x^y;", "19 expression expressions"],
  220. ["x|y;", "20 expression expressions"],
  221. ["x+y<z;", "21 expression expressions"],
  222. ["x<y+z;", "22 expression expressions"],
  223. ["x+y+z;", "23 expression expressions"],
  224. ["x+y<z;", "24 expression expressions"],
  225. ["x<y+z;", "25 expression expressions"],
  226. ["x&y|z;", "26 expression expressions"],
  227. ["x&&y;", "27 expression expressions"],
  228. ["x||y;", "28 expression expressions"],
  229. ["x&&y||z;", "29 expression expressions"],
  230. ["x||y&&z;", "30 expression expressions"],
  231. ["x<y?z:w;", "31 expression expressions"],
  232. // assignment
  233. ["x >>>= y;", "1 assignment"],
  234. ["x <<= y;", "2 assignment"],
  235. ["x = y;", "3 assignment"],
  236. ["x += y;", "4 assignment"],
  237. ["x /= y;", "5 assignment"],
  238. // comma
  239. ["x, y;", "comma"],
  240. // block
  241. ["{};", "1 block"],
  242. ["{x;};", "2 block"],
  243. ["{x;y;};", "3 block"],
  244. // vars
  245. ["var x;", "1 var"],
  246. ["var x,y;", "2 var"],
  247. ["var x=1,y=2;", "3 var"],
  248. ["var x,y=2;", "4 var"],
  249. // empty
  250. [";", "1 empty"],
  251. ["\n;", "2 empty"],
  252. // expression statement
  253. ["x;", "1 expression statement"],
  254. ["5;", "2 expression statement"],
  255. ["1+2;", "3 expression statement"],
  256. // if
  257. ["if (c) x; else y;", "1 if statement"],
  258. ["if (c) x;", "2 if statement"],
  259. ["if (c) {} else {};", "3 if statement"],
  260. ["if (c1) if (c2) s1; else s2;", "4 if statement"],
  261. // while
  262. ["do s; while (e);", "1 while statement"],
  263. ["do { s; } while (e);", "2 while statement"],
  264. ["while (e) s;", "3 while statement"],
  265. ["while (e) { s; };", "4 while statement"],
  266. // for
  267. ["for (;;) ;", "1 for statement"],
  268. ["for (;c;x++) x;", "2 for statement"],
  269. ["for (i;i<len;++i){};", "3 for statement"],
  270. ["for (var i=0;i<len;++i) {};", "4 for statement"],
  271. ["for (var i=0,j=0;;){};", "5 for statement"],
  272. //["for (x in b; c; u) {};", "6 for statement"],
  273. ["for ((x in b); c; u) {};", "7 for statement"],
  274. ["for (x in a);", "8 for statement"],
  275. ["for (var x in a){};", "9 for statement"],
  276. ["for (var x=5 in a) {};", "10 for statement"],
  277. ["for (var x = a in b in c) {};", "11 for statement"],
  278. ["for (var x=function(){a+b;}; a<b; ++i) some;", "11 for statement, testing for parsingForHeader reset with the function"],
  279. ["for (var x=function(){for (x=0; x<15; ++x) alert(foo); }; a<b; ++i) some;", "11 for statement, testing for parsingForHeader reset with the function"],
  280. // flow statements
  281. ["while(1){ continue; }", "1 flow statement"],
  282. ["label: while(1){ continue label; }", "2 flow statement"],
  283. ["while(1){ break; }", "3 flow statement"],
  284. ["somewhere: while(1){ break somewhere; }", "4 flow statement"],
  285. ["while(1){ continue /* comment */ ; }", "5 flow statement"],
  286. ["while(1){ continue \n; }", "6 flow statement"],
  287. ["(function(){ return; })()", "7 flow statement"],
  288. ["(function(){ return 0; })()", "8 flow statement"],
  289. ["(function(){ return 0 + \n 1; })()", "9 flow statement"],
  290. // with
  291. ["with (e) s;", "with statement"],
  292. // switch
  293. ["switch (e) { case x: s; };", "1 switch statement"],
  294. ["switch (e) { case x: s1;s2; default: s3; case y: s4; };", "2 switch statement"],
  295. ["switch (e) { default: s1; case x: s2; case y: s3; };", "3 switch statement"],
  296. ["switch (e) { default: s; };", "4 switch statement"],
  297. ["switch (e) { case x: s1; case y: s2; };", "5 switch statement"],
  298. // labels
  299. ["foo : x;", " flow statement"],
  300. // throw
  301. ["throw x;", "1 throw statement"],
  302. ["throw x\n;", "2 throw statement"],
  303. // try catch finally
  304. ["try { s1; } catch (e) { s2; };", "1 trycatchfinally statement"],
  305. ["try { s1; } finally { s2; };", "2 trycatchfinally statement"],
  306. ["try { s1; } catch (e) { s2; } finally { s3; };", "3 trycatchfinally statement"],
  307. // debugger
  308. ["debugger;", "debugger statement"],
  309. // function decl
  310. ["function f(x) { e; return x; };", "1 function declaration"],
  311. ["function f() { x; y; };", "2 function declaration"],
  312. ["function f(x,y) { var z; return x; };", "3 function declaration"],
  313. // function exp
  314. ["(function f(x) { return x; });", "1 function expression"],
  315. ["(function empty() {;});", "2 function expression"],
  316. ["(function empty() {;});", "3 function expression"],
  317. ["(function (x) {; });", "4 function expression"],
  318. // program
  319. ["var x; function f(){;}; null;", "1 program"],
  320. [";;", "2 program"],
  321. ["{ x; y; z; }", "3 program"],
  322. ["function f(){ function g(){;}};", "4 program"],
  323. ["x;\n/*foo*/\n ;", "5 program"],
  324. // asi
  325. ["foo: while(1){ continue \n foo; }", "1 asi"],
  326. ["foo: while(1){ break \n foo; }", "2 asi"],
  327. ["(function(){ return\nfoo; })()", "3 asi"],
  328. ["var x; { 1 \n 2 } 3", "4 asi"],
  329. ["ab /* hi */\ncd", "5 asi"],
  330. ["ab/*\n*/cd", "6 asi (multi line multilinecomment counts as eol)"],
  331. ["foo: while(1){ continue /* wtf \n busta */ foo; }", "7 asi illegal with multi line comment"],
  332. ["function f() { s }", "8 asi"],
  333. ["function f() { return }", "9 asi"],
  334. // use strict
  335. // XXX: some of these should actually fail?
  336. // no support for "use strict" yet...
  337. ['"use strict"; \'bla\'\n; foo;', "1 directive"],
  338. ['(function() { "use strict"; \'bla\';\n foo; });', "2 directive"],
  339. ['"use\\n strict";', "3 directive"],
  340. ['foo; "use strict";', "4 directive"],
  341. // tests from http://es5conform.codeplex.com/
  342. ['"use strict"; var o = { eval: 42};', "8.7.2-3-1-s: the use of eval as property name is allowed"],
  343. ['({foo:0,foo:1});', 'Duplicate property name allowed in not strict mode'],
  344. ['function foo(a,a){}', 'Duplicate parameter name allowed in not strict mode'],
  345. ['(function foo(eval){})', 'Eval allowed as parameter name in non strict mode'],
  346. ['(function foo(arguments){})', 'Arguments allowed as parameter name in non strict mode'],
  347. // empty programs
  348. ['', '1 Empty program'],
  349. ['// test', '2 Empty program'],
  350. ['//test\n', '3 Empty program'],
  351. ['\n// test', '4 Empty program'],
  352. ['\n// test\n', '5 Empty program'],
  353. ['/* */', '6 Empty program'],
  354. ['/*\ns,fd\n*/', '7 Empty program'],
  355. ['/*\ns,fd\n*/\n', '8 Empty program'],
  356. [' ', '9 Empty program'],
  357. [' /*\nsmeh*/ \n ', '10 Empty program'],
  358. // trailing whitespace
  359. ['a ', '1 Trailing whitespace'],
  360. ['a /* something */', '2 Trailing whitespace'],
  361. ['a\n // hah', '3 Trailing whitespace'],
  362. ['/abc/de//f', '4 Trailing whitespace'],
  363. ['/abc/de/*f*/\n ', '5 Trailing whitespace'],
  364. // things the parser tripped over at one point or the other (prevents regression bugs)
  365. ['for (x;function(){ a\nb };z) x;', 'for header with function body forcing ASI'],
  366. ['c=function(){return;return};', 'resetting noAsi after literal'],
  367. ['d\nd()', 'asi exception causing token overflow'],
  368. ['for(;;){x=function(){}}', 'function expression in a for header'],
  369. ['for(var k;;){}', 'parser failing due to ASI accepting the incorrect "for" rule'],
  370. ['({get foo(){ }})', 'getter with empty function body'],
  371. ['\nreturnr', 'eol causes return statement to ignore local search requirement'],
  372. [' / /', '1 whitespace before regex causes regex to fail?'],
  373. ['/ // / /', '2 whitespace before regex causes regex to fail?'],
  374. ['/ / / / /', '3 whitespace before regex causes regex to fail?'],
  375. ['\n\t// Used for trimming whitespace\n\ttrimLeft = /^\\s+/;\n\ttrimRight = /\\s+$/;\t\n','turned out this didnt crash (the test below did), but whatever.'],
  376. ['/[\\/]/;', 'escaped forward slash inside class group (would choke on fwd slash)'],
  377. ['/[/]/;', 'also broke but is valid in es5 (not es3)'],
  378. ['({get:5});','get property name thats not a getter'],
  379. ['({set:5});','set property name thats not a setter'],
  380. ['l !== "px" && (d.style(h, c, (k || 1) + l), j = (k || 1) / f.cur() * j, d.style(h, c, j + l)), i[1] && (k = (i[1] === "-=" ? -1 : 1) * k + j), f.custom(j, k, l)', 'this choked regex/div at some point'],
  381. ['(/\'/g, \'\\\\\\\'\') + "\'";', 'the sequence of escaped characters confused the tokenizer'],
  382. ['if (true) /=a/.test("a");', 'regexp starting with "=" in not obvious context (not implied by preceding token)']
  383. ];
  384. for (var i=0; i<inps.length; ++i) {
  385. callback(i, inps[i][0], inps[i][1]);
  386. };
  387. };