distil 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (552) hide show
  1. data/Rakefile +28 -0
  2. data/VERSION +1 -0
  3. data/bin/distil +45 -0
  4. data/distil.gemspec +586 -0
  5. data/lib/bootstrap-template.js +56 -0
  6. data/lib/configurable.rb +125 -0
  7. data/lib/file-set.rb +42 -0
  8. data/lib/file-types/css-file.rb +75 -0
  9. data/lib/file-types/html-file.rb +11 -0
  10. data/lib/file-types/javascript-file.rb +98 -0
  11. data/lib/file-types/json-file.rb +14 -0
  12. data/lib/file-types/nib-file.rb +9 -0
  13. data/lib/jsdoc.conf +18 -0
  14. data/lib/jsl.conf +121 -0
  15. data/lib/project.rb +96 -0
  16. data/lib/source-file.rb +181 -0
  17. data/lib/target.rb +96 -0
  18. data/lib/task.rb +239 -0
  19. data/lib/tasks/copy-task.rb +21 -0
  20. data/lib/tasks/css-task.rb +18 -0
  21. data/lib/tasks/javascript-task.rb +125 -0
  22. data/lib/tasks/multiple-output-task.rb +134 -0
  23. data/lib/tasks/nib-task.rb +83 -0
  24. data/lib/tasks/output-task.rb +73 -0
  25. data/lib/tasks/single-output-task.rb +83 -0
  26. data/lib/tasks/test-task.rb +280 -0
  27. data/lib/test/HtmlTestReporter.js +127 -0
  28. data/lib/test/Test.js +248 -0
  29. data/lib/test/TestReporter.js +79 -0
  30. data/lib/test/TestRunner.js +132 -0
  31. data/lib/test/browser.rb +97 -0
  32. data/lib/test/scriptwrapper.html +10 -0
  33. data/lib/test/unittest.html +127 -0
  34. data/vendor/Makefile +35 -0
  35. data/vendor/extconf.rb +3 -0
  36. data/vendor/jsdoc-extras/plugins/distil-plugin.js +142 -0
  37. data/vendor/jsdoc-extras/plugins/interface-plugin.js +36 -0
  38. data/vendor/jsdoc-extras/templates/coherent/allclasses.tmpl +17 -0
  39. data/vendor/jsdoc-extras/templates/coherent/allfiles.tmpl +53 -0
  40. data/vendor/jsdoc-extras/templates/coherent/class.tmpl +803 -0
  41. data/vendor/jsdoc-extras/templates/coherent/index.tmpl +37 -0
  42. data/vendor/jsdoc-extras/templates/coherent/publish.js +242 -0
  43. data/vendor/jsdoc-extras/templates/coherent/showdown.js +421 -0
  44. data/vendor/jsdoc-extras/templates/coherent/static/code-footer.html +3 -0
  45. data/vendor/jsdoc-extras/templates/coherent/static/code-header.html +7 -0
  46. data/vendor/jsdoc-extras/templates/coherent/static/default.css +297 -0
  47. data/vendor/jsdoc-extras/templates/coherent/static/header.html +2 -0
  48. data/vendor/jsdoc-extras/templates/coherent/static/index.html +19 -0
  49. data/vendor/jsdoc-extras/templates/coherent/symbol.tmpl +35 -0
  50. data/vendor/jsdoc-toolkit/README.txt +183 -0
  51. data/vendor/jsdoc-toolkit/app/frame/Chain.js +102 -0
  52. data/vendor/jsdoc-toolkit/app/frame/Dumper.js +144 -0
  53. data/vendor/jsdoc-toolkit/app/frame/Hash.js +84 -0
  54. data/vendor/jsdoc-toolkit/app/frame/Link.js +171 -0
  55. data/vendor/jsdoc-toolkit/app/frame/Namespace.js +10 -0
  56. data/vendor/jsdoc-toolkit/app/frame/Opt.js +134 -0
  57. data/vendor/jsdoc-toolkit/app/frame/Reflection.js +26 -0
  58. data/vendor/jsdoc-toolkit/app/frame/String.js +93 -0
  59. data/vendor/jsdoc-toolkit/app/frame/Testrun.js +129 -0
  60. data/vendor/jsdoc-toolkit/app/frame.js +33 -0
  61. data/vendor/jsdoc-toolkit/app/handlers/FOODOC.js +26 -0
  62. data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/DomReader.js +159 -0
  63. data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/XMLDoc.js +16 -0
  64. data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/XMLParse.js +292 -0
  65. data/vendor/jsdoc-toolkit/app/handlers/XMLDOC.js +26 -0
  66. data/vendor/jsdoc-toolkit/app/lib/JSDOC/DocComment.js +204 -0
  67. data/vendor/jsdoc-toolkit/app/lib/JSDOC/DocTag.js +300 -0
  68. data/vendor/jsdoc-toolkit/app/lib/JSDOC/JsDoc.js +126 -0
  69. data/vendor/jsdoc-toolkit/app/lib/JSDOC/JsPlate.js +109 -0
  70. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Lang.js +144 -0
  71. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Parser.js +144 -0
  72. data/vendor/jsdoc-toolkit/app/lib/JSDOC/PluginManager.js +33 -0
  73. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Symbol.js +644 -0
  74. data/vendor/jsdoc-toolkit/app/lib/JSDOC/SymbolSet.js +241 -0
  75. data/vendor/jsdoc-toolkit/app/lib/JSDOC/TextStream.js +41 -0
  76. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Token.js +18 -0
  77. data/vendor/jsdoc-toolkit/app/lib/JSDOC/TokenReader.js +332 -0
  78. data/vendor/jsdoc-toolkit/app/lib/JSDOC/TokenStream.js +133 -0
  79. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Util.js +32 -0
  80. data/vendor/jsdoc-toolkit/app/lib/JSDOC/Walker.js +499 -0
  81. data/vendor/jsdoc-toolkit/app/lib/JSDOC.js +106 -0
  82. data/vendor/jsdoc-toolkit/app/main.js +129 -0
  83. data/vendor/jsdoc-toolkit/app/plugins/commentSrcJson.js +20 -0
  84. data/vendor/jsdoc-toolkit/app/plugins/frameworkPrototype.js +16 -0
  85. data/vendor/jsdoc-toolkit/app/plugins/functionCall.js +10 -0
  86. data/vendor/jsdoc-toolkit/app/plugins/publishSrcHilite.js +54 -0
  87. data/vendor/jsdoc-toolkit/app/plugins/symbolLink.js +10 -0
  88. data/vendor/jsdoc-toolkit/app/plugins/tagParamConfig.js +31 -0
  89. data/vendor/jsdoc-toolkit/app/plugins/tagSynonyms.js +43 -0
  90. data/vendor/jsdoc-toolkit/app/run.js +348 -0
  91. data/vendor/jsdoc-toolkit/app/t/TestDoc.js +144 -0
  92. data/vendor/jsdoc-toolkit/app/t/runner.js +13 -0
  93. data/vendor/jsdoc-toolkit/app/test/addon.js +24 -0
  94. data/vendor/jsdoc-toolkit/app/test/anon_inner.js +14 -0
  95. data/vendor/jsdoc-toolkit/app/test/augments.js +31 -0
  96. data/vendor/jsdoc-toolkit/app/test/augments2.js +26 -0
  97. data/vendor/jsdoc-toolkit/app/test/borrows.js +46 -0
  98. data/vendor/jsdoc-toolkit/app/test/borrows2.js +23 -0
  99. data/vendor/jsdoc-toolkit/app/test/config.js +22 -0
  100. data/vendor/jsdoc-toolkit/app/test/constructs.js +18 -0
  101. data/vendor/jsdoc-toolkit/app/test/encoding.js +10 -0
  102. data/vendor/jsdoc-toolkit/app/test/encoding_other.js +12 -0
  103. data/vendor/jsdoc-toolkit/app/test/event.js +54 -0
  104. data/vendor/jsdoc-toolkit/app/test/exports.js +14 -0
  105. data/vendor/jsdoc-toolkit/app/test/functions_anon.js +39 -0
  106. data/vendor/jsdoc-toolkit/app/test/functions_nested.js +33 -0
  107. data/vendor/jsdoc-toolkit/app/test/global.js +13 -0
  108. data/vendor/jsdoc-toolkit/app/test/globals.js +25 -0
  109. data/vendor/jsdoc-toolkit/app/test/ignore.js +10 -0
  110. data/vendor/jsdoc-toolkit/app/test/inner.js +16 -0
  111. data/vendor/jsdoc-toolkit/app/test/jsdoc_test.js +477 -0
  112. data/vendor/jsdoc-toolkit/app/test/lend.js +33 -0
  113. data/vendor/jsdoc-toolkit/app/test/memberof.js +19 -0
  114. data/vendor/jsdoc-toolkit/app/test/memberof2.js +38 -0
  115. data/vendor/jsdoc-toolkit/app/test/memberof3.js +33 -0
  116. data/vendor/jsdoc-toolkit/app/test/memberof_constructor.js +17 -0
  117. data/vendor/jsdoc-toolkit/app/test/module.js +17 -0
  118. data/vendor/jsdoc-toolkit/app/test/name.js +19 -0
  119. data/vendor/jsdoc-toolkit/app/test/namespace_nested.js +23 -0
  120. data/vendor/jsdoc-toolkit/app/test/nocode.js +13 -0
  121. data/vendor/jsdoc-toolkit/app/test/oblit_anon.js +20 -0
  122. data/vendor/jsdoc-toolkit/app/test/overview.js +20 -0
  123. data/vendor/jsdoc-toolkit/app/test/param_inline.js +37 -0
  124. data/vendor/jsdoc-toolkit/app/test/params_optional.js +8 -0
  125. data/vendor/jsdoc-toolkit/app/test/prototype.js +17 -0
  126. data/vendor/jsdoc-toolkit/app/test/prototype_nested.js +9 -0
  127. data/vendor/jsdoc-toolkit/app/test/prototype_oblit.js +13 -0
  128. data/vendor/jsdoc-toolkit/app/test/prototype_oblit_constructor.js +24 -0
  129. data/vendor/jsdoc-toolkit/app/test/public.js +10 -0
  130. data/vendor/jsdoc-toolkit/app/test/scripts/code.js +5 -0
  131. data/vendor/jsdoc-toolkit/app/test/scripts/notcode.txt +5 -0
  132. data/vendor/jsdoc-toolkit/app/test/shared.js +42 -0
  133. data/vendor/jsdoc-toolkit/app/test/shared2.js +2 -0
  134. data/vendor/jsdoc-toolkit/app/test/shortcuts.js +22 -0
  135. data/vendor/jsdoc-toolkit/app/test/static_this.js +13 -0
  136. data/vendor/jsdoc-toolkit/app/test/synonyms.js +31 -0
  137. data/vendor/jsdoc-toolkit/app/test/tosource.js +23 -0
  138. data/vendor/jsdoc-toolkit/app/test/variable_redefine.js +14 -0
  139. data/vendor/jsdoc-toolkit/app/test.js +342 -0
  140. data/vendor/jsdoc-toolkit/changes.txt +116 -0
  141. data/vendor/jsdoc-toolkit/conf/sample.conf +31 -0
  142. data/vendor/jsdoc-toolkit/java/build.xml +36 -0
  143. data/vendor/jsdoc-toolkit/java/build_1.4.xml +36 -0
  144. data/vendor/jsdoc-toolkit/java/classes/js.jar +0 -0
  145. data/vendor/jsdoc-toolkit/java/src/JsDebugRun.java +21 -0
  146. data/vendor/jsdoc-toolkit/java/src/JsRun.java +21 -0
  147. data/vendor/jsdoc-toolkit/jsdebug.jar +0 -0
  148. data/vendor/jsdoc-toolkit/jsrun.jar +0 -0
  149. data/vendor/jsdoc-toolkit/jsrun.sh +53 -0
  150. data/vendor/jsdoc-toolkit/templates/jsdoc/allclasses.tmpl +17 -0
  151. data/vendor/jsdoc-toolkit/templates/jsdoc/allfiles.tmpl +56 -0
  152. data/vendor/jsdoc-toolkit/templates/jsdoc/class.tmpl +649 -0
  153. data/vendor/jsdoc-toolkit/templates/jsdoc/index.tmpl +39 -0
  154. data/vendor/jsdoc-toolkit/templates/jsdoc/publish.js +201 -0
  155. data/vendor/jsdoc-toolkit/templates/jsdoc/static/code-footer.html +3 -0
  156. data/vendor/jsdoc-toolkit/templates/jsdoc/static/code-header.html +14 -0
  157. data/vendor/jsdoc-toolkit/templates/jsdoc/static/default.css +162 -0
  158. data/vendor/jsdoc-toolkit/templates/jsdoc/static/header.html +2 -0
  159. data/vendor/jsdoc-toolkit/templates/jsdoc/static/index.html +19 -0
  160. data/vendor/jsdoc-toolkit/templates/jsdoc/symbol.tmpl +35 -0
  161. data/vendor/jsl-0.3.0/src/JavaScriptLintAPI.cpp +333 -0
  162. data/vendor/jsl-0.3.0/src/JavaScriptLintAPI.h +86 -0
  163. data/vendor/jsl-0.3.0/src/Makefile.in +375 -0
  164. data/vendor/jsl-0.3.0/src/Makefile.ref +372 -0
  165. data/vendor/jsl-0.3.0/src/README.html +826 -0
  166. data/vendor/jsl-0.3.0/src/SpiderMonkey.rsp +12 -0
  167. data/vendor/jsl-0.3.0/src/_jsl_online.php +223 -0
  168. data/vendor/jsl-0.3.0/src/config/AIX4.1.mk +65 -0
  169. data/vendor/jsl-0.3.0/src/config/AIX4.2.mk +64 -0
  170. data/vendor/jsl-0.3.0/src/config/AIX4.3.mk +65 -0
  171. data/vendor/jsl-0.3.0/src/config/Darwin.mk +81 -0
  172. data/vendor/jsl-0.3.0/src/config/Darwin1.3.mk +81 -0
  173. data/vendor/jsl-0.3.0/src/config/Darwin1.4.mk +41 -0
  174. data/vendor/jsl-0.3.0/src/config/Darwin5.2.mk +81 -0
  175. data/vendor/jsl-0.3.0/src/config/Darwin5.3.mk +81 -0
  176. data/vendor/jsl-0.3.0/src/config/HP-UXB.10.10.mk +77 -0
  177. data/vendor/jsl-0.3.0/src/config/HP-UXB.10.20.mk +77 -0
  178. data/vendor/jsl-0.3.0/src/config/HP-UXB.11.00.mk +80 -0
  179. data/vendor/jsl-0.3.0/src/config/IRIX.mk +87 -0
  180. data/vendor/jsl-0.3.0/src/config/IRIX5.3.mk +44 -0
  181. data/vendor/jsl-0.3.0/src/config/IRIX6.1.mk +44 -0
  182. data/vendor/jsl-0.3.0/src/config/IRIX6.2.mk +44 -0
  183. data/vendor/jsl-0.3.0/src/config/IRIX6.3.mk +44 -0
  184. data/vendor/jsl-0.3.0/src/config/IRIX6.5.mk +44 -0
  185. data/vendor/jsl-0.3.0/src/config/Linux_All.mk +103 -0
  186. data/vendor/jsl-0.3.0/src/config/Mac_OS10.0.mk +82 -0
  187. data/vendor/jsl-0.3.0/src/config/OSF1V4.0.mk +72 -0
  188. data/vendor/jsl-0.3.0/src/config/OSF1V5.0.mk +69 -0
  189. data/vendor/jsl-0.3.0/src/config/SunOS4.1.4.mk +101 -0
  190. data/vendor/jsl-0.3.0/src/config/SunOS5.3.mk +91 -0
  191. data/vendor/jsl-0.3.0/src/config/SunOS5.4.mk +92 -0
  192. data/vendor/jsl-0.3.0/src/config/SunOS5.5.1.mk +44 -0
  193. data/vendor/jsl-0.3.0/src/config/SunOS5.5.mk +87 -0
  194. data/vendor/jsl-0.3.0/src/config/SunOS5.6.mk +89 -0
  195. data/vendor/jsl-0.3.0/src/config/SunOS5.7.mk +44 -0
  196. data/vendor/jsl-0.3.0/src/config/SunOS5.8.mk +44 -0
  197. data/vendor/jsl-0.3.0/src/config/SunOS5.9.mk +44 -0
  198. data/vendor/jsl-0.3.0/src/config/WINNT4.0.mk +112 -0
  199. data/vendor/jsl-0.3.0/src/config/WINNT5.0.mk +112 -0
  200. data/vendor/jsl-0.3.0/src/config/WINNT5.1.mk +112 -0
  201. data/vendor/jsl-0.3.0/src/config/WINNT5.2.mk +112 -0
  202. data/vendor/jsl-0.3.0/src/config/dgux.mk +64 -0
  203. data/vendor/jsl-0.3.0/src/config.mk +166 -0
  204. data/vendor/jsl-0.3.0/src/editline/Makefile.ref +144 -0
  205. data/vendor/jsl-0.3.0/src/editline/README +83 -0
  206. data/vendor/jsl-0.3.0/src/editline/editline.3 +175 -0
  207. data/vendor/jsl-0.3.0/src/editline/editline.c +1369 -0
  208. data/vendor/jsl-0.3.0/src/editline/editline.h +135 -0
  209. data/vendor/jsl-0.3.0/src/editline/sysunix.c +182 -0
  210. data/vendor/jsl-0.3.0/src/editline/unix.h +82 -0
  211. data/vendor/jsl-0.3.0/src/fdlibm/Makefile.in +127 -0
  212. data/vendor/jsl-0.3.0/src/fdlibm/Makefile.ref +192 -0
  213. data/vendor/jsl-0.3.0/src/fdlibm/e_acos.c +147 -0
  214. data/vendor/jsl-0.3.0/src/fdlibm/e_acosh.c +105 -0
  215. data/vendor/jsl-0.3.0/src/fdlibm/e_asin.c +156 -0
  216. data/vendor/jsl-0.3.0/src/fdlibm/e_atan2.c +165 -0
  217. data/vendor/jsl-0.3.0/src/fdlibm/e_atanh.c +110 -0
  218. data/vendor/jsl-0.3.0/src/fdlibm/e_cosh.c +133 -0
  219. data/vendor/jsl-0.3.0/src/fdlibm/e_exp.c +202 -0
  220. data/vendor/jsl-0.3.0/src/fdlibm/e_fmod.c +184 -0
  221. data/vendor/jsl-0.3.0/src/fdlibm/e_gamma.c +71 -0
  222. data/vendor/jsl-0.3.0/src/fdlibm/e_gamma_r.c +70 -0
  223. data/vendor/jsl-0.3.0/src/fdlibm/e_hypot.c +173 -0
  224. data/vendor/jsl-0.3.0/src/fdlibm/e_j0.c +524 -0
  225. data/vendor/jsl-0.3.0/src/fdlibm/e_j1.c +523 -0
  226. data/vendor/jsl-0.3.0/src/fdlibm/e_jn.c +315 -0
  227. data/vendor/jsl-0.3.0/src/fdlibm/e_lgamma.c +71 -0
  228. data/vendor/jsl-0.3.0/src/fdlibm/e_lgamma_r.c +347 -0
  229. data/vendor/jsl-0.3.0/src/fdlibm/e_log.c +184 -0
  230. data/vendor/jsl-0.3.0/src/fdlibm/e_log10.c +134 -0
  231. data/vendor/jsl-0.3.0/src/fdlibm/e_pow.c +386 -0
  232. data/vendor/jsl-0.3.0/src/fdlibm/e_rem_pio2.c +221 -0
  233. data/vendor/jsl-0.3.0/src/fdlibm/e_remainder.c +120 -0
  234. data/vendor/jsl-0.3.0/src/fdlibm/e_scalb.c +89 -0
  235. data/vendor/jsl-0.3.0/src/fdlibm/e_sinh.c +122 -0
  236. data/vendor/jsl-0.3.0/src/fdlibm/e_sqrt.c +497 -0
  237. data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.dsp +160 -0
  238. data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.h +273 -0
  239. data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.mak +1453 -0
  240. data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.mdp +0 -0
  241. data/vendor/jsl-0.3.0/src/fdlibm/k_cos.c +134 -0
  242. data/vendor/jsl-0.3.0/src/fdlibm/k_rem_pio2.c +354 -0
  243. data/vendor/jsl-0.3.0/src/fdlibm/k_sin.c +114 -0
  244. data/vendor/jsl-0.3.0/src/fdlibm/k_standard.c +785 -0
  245. data/vendor/jsl-0.3.0/src/fdlibm/k_tan.c +170 -0
  246. data/vendor/jsl-0.3.0/src/fdlibm/s_asinh.c +101 -0
  247. data/vendor/jsl-0.3.0/src/fdlibm/s_atan.c +175 -0
  248. data/vendor/jsl-0.3.0/src/fdlibm/s_cbrt.c +133 -0
  249. data/vendor/jsl-0.3.0/src/fdlibm/s_ceil.c +120 -0
  250. data/vendor/jsl-0.3.0/src/fdlibm/s_copysign.c +72 -0
  251. data/vendor/jsl-0.3.0/src/fdlibm/s_cos.c +118 -0
  252. data/vendor/jsl-0.3.0/src/fdlibm/s_erf.c +356 -0
  253. data/vendor/jsl-0.3.0/src/fdlibm/s_expm1.c +267 -0
  254. data/vendor/jsl-0.3.0/src/fdlibm/s_fabs.c +70 -0
  255. data/vendor/jsl-0.3.0/src/fdlibm/s_finite.c +71 -0
  256. data/vendor/jsl-0.3.0/src/fdlibm/s_floor.c +121 -0
  257. data/vendor/jsl-0.3.0/src/fdlibm/s_frexp.c +99 -0
  258. data/vendor/jsl-0.3.0/src/fdlibm/s_ilogb.c +85 -0
  259. data/vendor/jsl-0.3.0/src/fdlibm/s_isnan.c +74 -0
  260. data/vendor/jsl-0.3.0/src/fdlibm/s_ldexp.c +66 -0
  261. data/vendor/jsl-0.3.0/src/fdlibm/s_lib_version.c +73 -0
  262. data/vendor/jsl-0.3.0/src/fdlibm/s_log1p.c +211 -0
  263. data/vendor/jsl-0.3.0/src/fdlibm/s_logb.c +79 -0
  264. data/vendor/jsl-0.3.0/src/fdlibm/s_matherr.c +64 -0
  265. data/vendor/jsl-0.3.0/src/fdlibm/s_modf.c +132 -0
  266. data/vendor/jsl-0.3.0/src/fdlibm/s_nextafter.c +124 -0
  267. data/vendor/jsl-0.3.0/src/fdlibm/s_rint.c +131 -0
  268. data/vendor/jsl-0.3.0/src/fdlibm/s_scalbn.c +107 -0
  269. data/vendor/jsl-0.3.0/src/fdlibm/s_signgam.c +40 -0
  270. data/vendor/jsl-0.3.0/src/fdlibm/s_significand.c +68 -0
  271. data/vendor/jsl-0.3.0/src/fdlibm/s_sin.c +118 -0
  272. data/vendor/jsl-0.3.0/src/fdlibm/s_tan.c +112 -0
  273. data/vendor/jsl-0.3.0/src/fdlibm/s_tanh.c +122 -0
  274. data/vendor/jsl-0.3.0/src/fdlibm/w_acos.c +78 -0
  275. data/vendor/jsl-0.3.0/src/fdlibm/w_acosh.c +78 -0
  276. data/vendor/jsl-0.3.0/src/fdlibm/w_asin.c +80 -0
  277. data/vendor/jsl-0.3.0/src/fdlibm/w_atan2.c +79 -0
  278. data/vendor/jsl-0.3.0/src/fdlibm/w_atanh.c +81 -0
  279. data/vendor/jsl-0.3.0/src/fdlibm/w_cosh.c +77 -0
  280. data/vendor/jsl-0.3.0/src/fdlibm/w_exp.c +88 -0
  281. data/vendor/jsl-0.3.0/src/fdlibm/w_fmod.c +78 -0
  282. data/vendor/jsl-0.3.0/src/fdlibm/w_gamma.c +85 -0
  283. data/vendor/jsl-0.3.0/src/fdlibm/w_gamma_r.c +81 -0
  284. data/vendor/jsl-0.3.0/src/fdlibm/w_hypot.c +78 -0
  285. data/vendor/jsl-0.3.0/src/fdlibm/w_j0.c +105 -0
  286. data/vendor/jsl-0.3.0/src/fdlibm/w_j1.c +106 -0
  287. data/vendor/jsl-0.3.0/src/fdlibm/w_jn.c +128 -0
  288. data/vendor/jsl-0.3.0/src/fdlibm/w_lgamma.c +85 -0
  289. data/vendor/jsl-0.3.0/src/fdlibm/w_lgamma_r.c +81 -0
  290. data/vendor/jsl-0.3.0/src/fdlibm/w_log.c +78 -0
  291. data/vendor/jsl-0.3.0/src/fdlibm/w_log10.c +81 -0
  292. data/vendor/jsl-0.3.0/src/fdlibm/w_pow.c +99 -0
  293. data/vendor/jsl-0.3.0/src/fdlibm/w_remainder.c +77 -0
  294. data/vendor/jsl-0.3.0/src/fdlibm/w_scalb.c +95 -0
  295. data/vendor/jsl-0.3.0/src/fdlibm/w_sinh.c +77 -0
  296. data/vendor/jsl-0.3.0/src/fdlibm/w_sqrt.c +77 -0
  297. data/vendor/jsl-0.3.0/src/js.c +2447 -0
  298. data/vendor/jsl-0.3.0/src/js.dsp +420 -0
  299. data/vendor/jsl-0.3.0/src/js.mak +4025 -0
  300. data/vendor/jsl-0.3.0/src/js.mdp +0 -0
  301. data/vendor/jsl-0.3.0/src/js.msg +291 -0
  302. data/vendor/jsl-0.3.0/src/js.pkg +2 -0
  303. data/vendor/jsl-0.3.0/src/js3240.rc +79 -0
  304. data/vendor/jsl-0.3.0/src/jsOS240.def +654 -0
  305. data/vendor/jsl-0.3.0/src/jsapi.c +4405 -0
  306. data/vendor/jsl-0.3.0/src/jsapi.h +1856 -0
  307. data/vendor/jsl-0.3.0/src/jsarena.c +567 -0
  308. data/vendor/jsl-0.3.0/src/jsarena.h +302 -0
  309. data/vendor/jsl-0.3.0/src/jsarray.c +1428 -0
  310. data/vendor/jsl-0.3.0/src/jsarray.h +77 -0
  311. data/vendor/jsl-0.3.0/src/jsatom.c +927 -0
  312. data/vendor/jsl-0.3.0/src/jsatom.h +426 -0
  313. data/vendor/jsl-0.3.0/src/jsbit.h +113 -0
  314. data/vendor/jsl-0.3.0/src/jsbool.c +220 -0
  315. data/vendor/jsl-0.3.0/src/jsbool.h +62 -0
  316. data/vendor/jsl-0.3.0/src/jsclist.h +139 -0
  317. data/vendor/jsl-0.3.0/src/jscntxt.c +1036 -0
  318. data/vendor/jsl-0.3.0/src/jscntxt.h +608 -0
  319. data/vendor/jsl-0.3.0/src/jscompat.h +57 -0
  320. data/vendor/jsl-0.3.0/src/jsconfig.h +489 -0
  321. data/vendor/jsl-0.3.0/src/jsconfig.mk +181 -0
  322. data/vendor/jsl-0.3.0/src/jscpucfg.c +377 -0
  323. data/vendor/jsl-0.3.0/src/jscpucfg.h +204 -0
  324. data/vendor/jsl-0.3.0/src/jsdate.c +2238 -0
  325. data/vendor/jsl-0.3.0/src/jsdate.h +118 -0
  326. data/vendor/jsl-0.3.0/src/jsdbgapi.c +1260 -0
  327. data/vendor/jsl-0.3.0/src/jsdbgapi.h +345 -0
  328. data/vendor/jsl-0.3.0/src/jsdhash.c +763 -0
  329. data/vendor/jsl-0.3.0/src/jsdhash.h +579 -0
  330. data/vendor/jsl-0.3.0/src/jsdtoa.c +3135 -0
  331. data/vendor/jsl-0.3.0/src/jsdtoa.h +130 -0
  332. data/vendor/jsl-0.3.0/src/jsemit.c +4851 -0
  333. data/vendor/jsl-0.3.0/src/jsemit.h +576 -0
  334. data/vendor/jsl-0.3.0/src/jsexn.c +1084 -0
  335. data/vendor/jsl-0.3.0/src/jsexn.h +102 -0
  336. data/vendor/jsl-0.3.0/src/jsfile.c +2610 -0
  337. data/vendor/jsl-0.3.0/src/jsfile.h +50 -0
  338. data/vendor/jsl-0.3.0/src/jsfile.msg +89 -0
  339. data/vendor/jsl-0.3.0/src/jsfun.c +2015 -0
  340. data/vendor/jsl-0.3.0/src/jsfun.h +158 -0
  341. data/vendor/jsl-0.3.0/src/jsgc.c +1441 -0
  342. data/vendor/jsl-0.3.0/src/jsgc.h +230 -0
  343. data/vendor/jsl-0.3.0/src/jshash.c +471 -0
  344. data/vendor/jsl-0.3.0/src/jshash.h +152 -0
  345. data/vendor/jsl-0.3.0/src/jsify.pl +485 -0
  346. data/vendor/jsl-0.3.0/src/jsinterp.c +4797 -0
  347. data/vendor/jsl-0.3.0/src/jsinterp.h +302 -0
  348. data/vendor/jsl-0.3.0/src/jsl-test.js +28 -0
  349. data/vendor/jsl-0.3.0/src/jsl.c +2371 -0
  350. data/vendor/jsl-0.3.0/src/jsl.conf +127 -0
  351. data/vendor/jsl-0.3.0/src/jsl.conf.old +124 -0
  352. data/vendor/jsl-0.3.0/src/jsl.dsp +242 -0
  353. data/vendor/jsl-0.3.0/src/jsl.dsw +59 -0
  354. data/vendor/jsl-0.3.0/src/jslibmath.h +290 -0
  355. data/vendor/jsl-0.3.0/src/jslock.c +1261 -0
  356. data/vendor/jsl-0.3.0/src/jslock.h +289 -0
  357. data/vendor/jsl-0.3.0/src/jslocko.asm +59 -0
  358. data/vendor/jsl-0.3.0/src/jslog2.c +83 -0
  359. data/vendor/jsl-0.3.0/src/jslong.c +281 -0
  360. data/vendor/jsl-0.3.0/src/jslong.h +437 -0
  361. data/vendor/jsl-0.3.0/src/jsmath.c +477 -0
  362. data/vendor/jsl-0.3.0/src/jsmath.h +55 -0
  363. data/vendor/jsl-0.3.0/src/jsnum.c +1148 -0
  364. data/vendor/jsl-0.3.0/src/jsnum.h +257 -0
  365. data/vendor/jsl-0.3.0/src/jsobj.c +4066 -0
  366. data/vendor/jsl-0.3.0/src/jsobj.h +475 -0
  367. data/vendor/jsl-0.3.0/src/jsopcode.c +2730 -0
  368. data/vendor/jsl-0.3.0/src/jsopcode.h +275 -0
  369. data/vendor/jsl-0.3.0/src/jsopcode.tbl +344 -0
  370. data/vendor/jsl-0.3.0/src/jsosdep.h +127 -0
  371. data/vendor/jsl-0.3.0/src/jsotypes.h +211 -0
  372. data/vendor/jsl-0.3.0/src/jsparse.c +4438 -0
  373. data/vendor/jsl-0.3.0/src/jsparse.h +345 -0
  374. data/vendor/jsl-0.3.0/src/jsprf.c +1212 -0
  375. data/vendor/jsl-0.3.0/src/jsprf.h +148 -0
  376. data/vendor/jsl-0.3.0/src/jsprvtd.h +174 -0
  377. data/vendor/jsl-0.3.0/src/jspubtd.h +586 -0
  378. data/vendor/jsl-0.3.0/src/jsregexp.c +3831 -0
  379. data/vendor/jsl-0.3.0/src/jsregexp.h +180 -0
  380. data/vendor/jsl-0.3.0/src/jsscan.c +1814 -0
  381. data/vendor/jsl-0.3.0/src/jsscan.h +267 -0
  382. data/vendor/jsl-0.3.0/src/jsscope.c +1639 -0
  383. data/vendor/jsl-0.3.0/src/jsscope.h +389 -0
  384. data/vendor/jsl-0.3.0/src/jsscript.c +1284 -0
  385. data/vendor/jsl-0.3.0/src/jsscript.h +179 -0
  386. data/vendor/jsl-0.3.0/src/jsshell.msg +50 -0
  387. data/vendor/jsl-0.3.0/src/jsstddef.h +83 -0
  388. data/vendor/jsl-0.3.0/src/jsstr.c +4502 -0
  389. data/vendor/jsl-0.3.0/src/jsstr.h +448 -0
  390. data/vendor/jsl-0.3.0/src/jstypes.h +391 -0
  391. data/vendor/jsl-0.3.0/src/jsutil.c +157 -0
  392. data/vendor/jsl-0.3.0/src/jsutil.h +75 -0
  393. data/vendor/jsl-0.3.0/src/jsxdrapi.c +686 -0
  394. data/vendor/jsl-0.3.0/src/jsxdrapi.h +193 -0
  395. data/vendor/jsl-0.3.0/src/liveconnect/LiveConnect.dsp +157 -0
  396. data/vendor/jsl-0.3.0/src/liveconnect/LiveConnectShell.dsp +120 -0
  397. data/vendor/jsl-0.3.0/src/liveconnect/LiveConnectShell.dsw +44 -0
  398. data/vendor/jsl-0.3.0/src/liveconnect/Makefile.in +106 -0
  399. data/vendor/jsl-0.3.0/src/liveconnect/Makefile.ref +169 -0
  400. data/vendor/jsl-0.3.0/src/liveconnect/README.html +719 -0
  401. data/vendor/jsl-0.3.0/src/liveconnect/_jni/netscape_javascript_JSException.h +14 -0
  402. data/vendor/jsl-0.3.0/src/liveconnect/_jni/netscape_javascript_JSObject.h +155 -0
  403. data/vendor/jsl-0.3.0/src/liveconnect/classes/Makefile.in +89 -0
  404. data/vendor/jsl-0.3.0/src/liveconnect/classes/Makefile.ref +57 -0
  405. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/Makefile.ref +47 -0
  406. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSException.java +140 -0
  407. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSObject.java +183 -0
  408. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSProxy.java +58 -0
  409. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSRunnable.java +70 -0
  410. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSUtil.java +59 -0
  411. data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/Makefile.ref +53 -0
  412. data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.1.mk +45 -0
  413. data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.2.mk +45 -0
  414. data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.3.mk +50 -0
  415. data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.10.10.mk +43 -0
  416. data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.10.20.mk +43 -0
  417. data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.11.00.mk +43 -0
  418. data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.2.mk +43 -0
  419. data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.3.mk +43 -0
  420. data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.5.mk +43 -0
  421. data/vendor/jsl-0.3.0/src/liveconnect/config/Linux_All.mk +73 -0
  422. data/vendor/jsl-0.3.0/src/liveconnect/config/OSF1V4.0.mk +65 -0
  423. data/vendor/jsl-0.3.0/src/liveconnect/config/OSF1V5.0.mk +62 -0
  424. data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.5.1.mk +55 -0
  425. data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.6.mk +39 -0
  426. data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.7.mk +39 -0
  427. data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.8.mk +39 -0
  428. data/vendor/jsl-0.3.0/src/liveconnect/config/WINNT4.0.mk +53 -0
  429. data/vendor/jsl-0.3.0/src/liveconnect/jsj.c +884 -0
  430. data/vendor/jsl-0.3.0/src/liveconnect/jsj.msg +98 -0
  431. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JSObject.c +1379 -0
  432. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaArray.c +481 -0
  433. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaClass.c +749 -0
  434. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaMember.c +186 -0
  435. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaObject.c +1099 -0
  436. data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaPackage.c +548 -0
  437. data/vendor/jsl-0.3.0/src/liveconnect/jsj_array.c +207 -0
  438. data/vendor/jsl-0.3.0/src/liveconnect/jsj_class.c +765 -0
  439. data/vendor/jsl-0.3.0/src/liveconnect/jsj_convert.c +954 -0
  440. data/vendor/jsl-0.3.0/src/liveconnect/jsj_field.c +421 -0
  441. data/vendor/jsl-0.3.0/src/liveconnect/jsj_hash.c +504 -0
  442. data/vendor/jsl-0.3.0/src/liveconnect/jsj_hash.h +161 -0
  443. data/vendor/jsl-0.3.0/src/liveconnect/jsj_method.c +1823 -0
  444. data/vendor/jsl-0.3.0/src/liveconnect/jsj_nodl.c +1 -0
  445. data/vendor/jsl-0.3.0/src/liveconnect/jsj_private.h +689 -0
  446. data/vendor/jsl-0.3.0/src/liveconnect/jsj_simpleapi.c +219 -0
  447. data/vendor/jsl-0.3.0/src/liveconnect/jsj_utils.c +513 -0
  448. data/vendor/jsl-0.3.0/src/liveconnect/jsjava.h +313 -0
  449. data/vendor/jsl-0.3.0/src/liveconnect/liveconnect.pkg +3 -0
  450. data/vendor/jsl-0.3.0/src/liveconnect/netscape_javascript_JSObject.h +155 -0
  451. data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnect.cpp +785 -0
  452. data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnect.h +197 -0
  453. data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnectFactory.cpp +163 -0
  454. data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnectFactory.h +76 -0
  455. data/vendor/jsl-0.3.0/src/liveconnect/nsILiveconnect.h +195 -0
  456. data/vendor/jsl-0.3.0/src/liveconnect/nsISecureLiveconnect.h +84 -0
  457. data/vendor/jsl-0.3.0/src/liveconnect/nsISecurityContext.h +135 -0
  458. data/vendor/jsl-0.3.0/src/liveconnect/win32.order +6 -0
  459. data/vendor/jsl-0.3.0/src/lock_SunOS.s +114 -0
  460. data/vendor/jsl-0.3.0/src/perfect.js +39 -0
  461. data/vendor/jsl-0.3.0/src/perlconnect/JS.def +6 -0
  462. data/vendor/jsl-0.3.0/src/perlconnect/JS.dsp +107 -0
  463. data/vendor/jsl-0.3.0/src/perlconnect/JS.pm +318 -0
  464. data/vendor/jsl-0.3.0/src/perlconnect/JS.xs +1050 -0
  465. data/vendor/jsl-0.3.0/src/perlconnect/Makefile.PL +67 -0
  466. data/vendor/jsl-0.3.0/src/perlconnect/Makefile.ref +152 -0
  467. data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.dsp +103 -0
  468. data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.dsw +59 -0
  469. data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.pm +126 -0
  470. data/vendor/jsl-0.3.0/src/perlconnect/PerlConnectShell.dsp +89 -0
  471. data/vendor/jsl-0.3.0/src/perlconnect/README.html +345 -0
  472. data/vendor/jsl-0.3.0/src/perlconnect/bg.jpg +0 -0
  473. data/vendor/jsl-0.3.0/src/perlconnect/jsperl.c +1100 -0
  474. data/vendor/jsl-0.3.0/src/perlconnect/jsperl.h +52 -0
  475. data/vendor/jsl-0.3.0/src/perlconnect/jsperlbuild.pl +81 -0
  476. data/vendor/jsl-0.3.0/src/perlconnect/jsperlpvt.h +57 -0
  477. data/vendor/jsl-0.3.0/src/perlconnect/test.js +73 -0
  478. data/vendor/jsl-0.3.0/src/perlconnect/test.pl +244 -0
  479. data/vendor/jsl-0.3.0/src/perlconnect/typemap +121 -0
  480. data/vendor/jsl-0.3.0/src/plify_jsdhash.sed +31 -0
  481. data/vendor/jsl-0.3.0/src/prmjtime.c +646 -0
  482. data/vendor/jsl-0.3.0/src/prmjtime.h +95 -0
  483. data/vendor/jsl-0.3.0/src/resource.h +15 -0
  484. data/vendor/jsl-0.3.0/src/rules.mk +193 -0
  485. data/vendor/jsl-0.3.0/src/win32.order +391 -0
  486. data/vendor/jsl-0.3.0/tests/conf/always_use_option_explicit.js +4 -0
  487. data/vendor/jsl-0.3.0/tests/conf/define.js +8 -0
  488. data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-1.js +7 -0
  489. data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-2.js +8 -0
  490. data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-3.js +27 -0
  491. data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-4.js +4 -0
  492. data/vendor/jsl-0.3.0/tests/conf/lambda_assign_requires_semicolon.js +24 -0
  493. data/vendor/jsl-0.3.0/tests/conf/legacy_control_comments.js +8 -0
  494. data/vendor/jsl-0.3.0/tests/control_comments/control_comments.js +33 -0
  495. data/vendor/jsl-0.3.0/tests/control_comments/declare.js +26 -0
  496. data/vendor/jsl-0.3.0/tests/control_comments/import-overflow.js +9 -0
  497. data/vendor/jsl-0.3.0/tests/control_comments/import.js +5 -0
  498. data/vendor/jsl-0.3.0/tests/control_comments/import2.js +2 -0
  499. data/vendor/jsl-0.3.0/tests/control_comments/invalid_fallthru.js +13 -0
  500. data/vendor/jsl-0.3.0/tests/control_comments/option_explicit-with.js +12 -0
  501. data/vendor/jsl-0.3.0/tests/control_comments/option_explicit.js +64 -0
  502. data/vendor/jsl-0.3.0/tests/errors/unterminated_comment.js +8 -0
  503. data/vendor/jsl-0.3.0/tests/html/script_tag_in_js_literal.html +14 -0
  504. data/vendor/jsl-0.3.0/tests/run_tests.pl +71 -0
  505. data/vendor/jsl-0.3.0/tests/warnings/ambiguous_else_stmt.js +21 -0
  506. data/vendor/jsl-0.3.0/tests/warnings/ambiguous_nested_stmt.js +66 -0
  507. data/vendor/jsl-0.3.0/tests/warnings/ambiguous_newline.js +261 -0
  508. data/vendor/jsl-0.3.0/tests/warnings/anon_no_return_value.js +26 -0
  509. data/vendor/jsl-0.3.0/tests/warnings/assign_to_function_call.js +16 -0
  510. data/vendor/jsl-0.3.0/tests/warnings/block_without_braces.js +13 -0
  511. data/vendor/jsl-0.3.0/tests/warnings/comma_separated_stmts.js +17 -0
  512. data/vendor/jsl-0.3.0/tests/warnings/comparison_type_conv.js +44 -0
  513. data/vendor/jsl-0.3.0/tests/warnings/default_not_at_end.js +15 -0
  514. data/vendor/jsl-0.3.0/tests/warnings/dup_option_explicit.js +5 -0
  515. data/vendor/jsl-0.3.0/tests/warnings/duplicate_case_in_switch.js +62 -0
  516. data/vendor/jsl-0.3.0/tests/warnings/duplicate_formal.js +5 -0
  517. data/vendor/jsl-0.3.0/tests/warnings/empty_statement.js +29 -0
  518. data/vendor/jsl-0.3.0/tests/warnings/equal_as_assign.js +7 -0
  519. data/vendor/jsl-0.3.0/tests/warnings/inc_dec_within_stmt-ignore.js +21 -0
  520. data/vendor/jsl-0.3.0/tests/warnings/inc_dec_within_stmt.js +63 -0
  521. data/vendor/jsl-0.3.0/tests/warnings/jsl_cc_not_understood.js +5 -0
  522. data/vendor/jsl-0.3.0/tests/warnings/leading_decimal_point.js +7 -0
  523. data/vendor/jsl-0.3.0/tests/warnings/legacy_cc_not_understood.js +9 -0
  524. data/vendor/jsl-0.3.0/tests/warnings/meaningless_block.js +12 -0
  525. data/vendor/jsl-0.3.0/tests/warnings/misplaced_regex.js +20 -0
  526. data/vendor/jsl-0.3.0/tests/warnings/missing_break.js +87 -0
  527. data/vendor/jsl-0.3.0/tests/warnings/missing_break_for_last_case.js +19 -0
  528. data/vendor/jsl-0.3.0/tests/warnings/missing_default_case.js +51 -0
  529. data/vendor/jsl-0.3.0/tests/warnings/missing_option_explicit.js +5 -0
  530. data/vendor/jsl-0.3.0/tests/warnings/missing_semicolon.js +19 -0
  531. data/vendor/jsl-0.3.0/tests/warnings/multiple_plus_minus.js +10 -0
  532. data/vendor/jsl-0.3.0/tests/warnings/nested_comment.js +6 -0
  533. data/vendor/jsl-0.3.0/tests/warnings/no_return_value.js +25 -0
  534. data/vendor/jsl-0.3.0/tests/warnings/octal_number.js +5 -0
  535. data/vendor/jsl-0.3.0/tests/warnings/parseint_missing_radix.js +15 -0
  536. data/vendor/jsl-0.3.0/tests/warnings/partial_option_explicit.js +5 -0
  537. data/vendor/jsl-0.3.0/tests/warnings/redeclared_var.js +10 -0
  538. data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/bad_backref.js +5 -0
  539. data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/deprecated_usage.js +11 -0
  540. data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/invalid_backref.js +5 -0
  541. data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/trailing_comma.js +5 -0
  542. data/vendor/jsl-0.3.0/tests/warnings/trailing_comma_in_array.js +8 -0
  543. data/vendor/jsl-0.3.0/tests/warnings/trailing_decimal_point.js +7 -0
  544. data/vendor/jsl-0.3.0/tests/warnings/unreachable_code.js +29 -0
  545. data/vendor/jsl-0.3.0/tests/warnings/use_of_label.js +19 -0
  546. data/vendor/jsl-0.3.0/tests/warnings/useless_assign.js +20 -0
  547. data/vendor/jsl-0.3.0/tests/warnings/useless_comparison.js +55 -0
  548. data/vendor/jsl-0.3.0/tests/warnings/useless_void.js +6 -0
  549. data/vendor/jsl-0.3.0/tests/warnings/var_hides_arg.js +4 -0
  550. data/vendor/jsl-0.3.0/tests/warnings/with_statement.js +7 -0
  551. data/vendor/yuicompressor-2.4.2.jar +0 -0
  552. metadata +605 -0
@@ -0,0 +1,4438 @@
1
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
+ *
3
+ * ***** BEGIN LICENSE BLOCK *****
4
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
+ *
6
+ * The contents of this file are subject to the Mozilla Public License Version
7
+ * 1.1 (the "License"); you may not use this file except in compliance with
8
+ * the License. You may obtain a copy of the License at
9
+ * http://www.mozilla.org/MPL/
10
+ *
11
+ * Software distributed under the License is distributed on an "AS IS" basis,
12
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
+ * for the specific language governing rights and limitations under the
14
+ * License.
15
+ *
16
+ * The Original Code is Mozilla Communicator client code, released
17
+ * March 31, 1998.
18
+ *
19
+ * The Initial Developer of the Original Code is
20
+ * Netscape Communications Corporation.
21
+ * Portions created by the Initial Developer are Copyright (C) 1998
22
+ * the Initial Developer. All Rights Reserved.
23
+ *
24
+ * Contributor(s):
25
+ *
26
+ * Alternatively, the contents of this file may be used under the terms of
27
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
28
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
+ * in which case the provisions of the GPL or the LGPL are applicable instead
30
+ * of those above. If you wish to allow use of your version of this file only
31
+ * under the terms of either the GPL or the LGPL, and not to allow others to
32
+ * use your version of this file under the terms of the MPL, indicate your
33
+ * decision by deleting the provisions above and replace them with the notice
34
+ * and other provisions required by the GPL or the LGPL. If you do not delete
35
+ * the provisions above, a recipient may use your version of this file under
36
+ * the terms of any one of the MPL, the GPL or the LGPL.
37
+ *
38
+ * ***** END LICENSE BLOCK ***** */
39
+
40
+ /*
41
+ * JS parser.
42
+ *
43
+ * This is a recursive-descent parser for the JavaScript language specified by
44
+ * "The JavaScript 1.5 Language Specification". It uses lexical and semantic
45
+ * feedback to disambiguate non-LL(1) structures. It generates trees of nodes
46
+ * induced by the recursive parsing (not precise syntax trees, see jsparse.h).
47
+ * After tree construction, it rewrites trees to fold constants and evaluate
48
+ * compile-time expressions. Finally, it calls js_EmitTree (see jsemit.h) to
49
+ * generate bytecode.
50
+ *
51
+ * This parser attempts no error recovery. The dense JSTokenType enumeration
52
+ * was designed with error recovery built on 64-bit first and follow bitsets
53
+ * in mind, however.
54
+ */
55
+ #include "jsstddef.h"
56
+ #include <stdlib.h>
57
+ #include <string.h>
58
+ #include <math.h>
59
+ #include "jstypes.h"
60
+ #include "jsarena.h" /* Added by JSIFY */
61
+ #include "jsutil.h" /* Added by JSIFY */
62
+ #include "jsapi.h"
63
+ #include "jsatom.h"
64
+ #include "jscntxt.h"
65
+ #include "jsconfig.h"
66
+ #include "jsemit.h"
67
+ #include "jsfun.h"
68
+ #include "jsinterp.h"
69
+ #include "jslock.h"
70
+ #include "jsnum.h"
71
+ #include "jsobj.h"
72
+ #include "jsopcode.h"
73
+ #include "jsparse.h"
74
+ #include "jsscan.h"
75
+ #include "jsscope.h"
76
+ #include "jsscript.h"
77
+ #include "jsstr.h"
78
+
79
+ /*
80
+ * JS parsers, from lowest to highest precedence.
81
+ *
82
+ * Each parser takes a context and a token stream, and emits bytecode using
83
+ * a code generator.
84
+ */
85
+
86
+ typedef JSParseNode *
87
+ JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc);
88
+
89
+ typedef JSParseNode *
90
+ JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
91
+ JSBool allowCallSyntax);
92
+
93
+ static JSParser FunctionStmt;
94
+ #if JS_HAS_LEXICAL_CLOSURE
95
+ static JSParser FunctionExpr;
96
+ #endif
97
+ static JSParser Statements;
98
+ static JSParser Statement;
99
+ static JSParser Variables;
100
+ static JSParser Expr;
101
+ static JSParser AssignExpr;
102
+ static JSParser CondExpr;
103
+ static JSParser OrExpr;
104
+ static JSParser AndExpr;
105
+ static JSParser BitOrExpr;
106
+ static JSParser BitXorExpr;
107
+ static JSParser BitAndExpr;
108
+ static JSParser EqExpr;
109
+ static JSParser RelExpr;
110
+ static JSParser ShiftExpr;
111
+ static JSParser AddExpr;
112
+ static JSParser MulExpr;
113
+ static JSParser UnaryExpr;
114
+ static JSMemberParser MemberExpr;
115
+ static JSParser PrimaryExpr;
116
+
117
+ /*
118
+ * Insist that the next token be of type tt, or report errno and return null.
119
+ * NB: this macro uses cx and ts from its lexical environment.
120
+ */
121
+ #define MUST_MATCH_TOKEN(tt, errno) \
122
+ JS_BEGIN_MACRO \
123
+ if (js_GetToken(cx, ts) != tt) { \
124
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \
125
+ return NULL; \
126
+ } \
127
+ JS_END_MACRO
128
+
129
+ #define CHECK_RECURSION() \
130
+ JS_BEGIN_MACRO \
131
+ int stackDummy; \
132
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { \
133
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, \
134
+ JSMSG_OVER_RECURSED); \
135
+ return NULL; \
136
+ } \
137
+ JS_END_MACRO
138
+
139
+ #ifdef METER_PARSENODES
140
+ static uint32 parsenodes = 0;
141
+ static uint32 maxparsenodes = 0;
142
+ static uint32 recyclednodes = 0;
143
+ #endif
144
+
145
+ static void
146
+ RecycleTree(JSParseNode *pn, JSTreeContext *tc)
147
+ {
148
+ if (!pn)
149
+ return;
150
+ JS_ASSERT(pn != tc->nodeList); /* catch back-to-back dup recycles */
151
+ pn->pn_next = tc->nodeList;
152
+ tc->nodeList = pn;
153
+ #ifdef METER_PARSENODES
154
+ recyclednodes++;
155
+ #endif
156
+ }
157
+
158
+ static JSParseNode *
159
+ NewOrRecycledNode(JSContext *cx, JSTreeContext *tc)
160
+ {
161
+ JSParseNode *pn;
162
+
163
+ pn = tc->nodeList;
164
+ if (!pn) {
165
+ JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
166
+ if (!pn)
167
+ JS_ReportOutOfMemory(cx);
168
+ } else {
169
+ tc->nodeList = pn->pn_next;
170
+
171
+ /* Recycle immediate descendents only, to save work and working set. */
172
+ switch (pn->pn_arity) {
173
+ case PN_FUNC:
174
+ RecycleTree(pn->pn_body, tc);
175
+ break;
176
+ case PN_LIST:
177
+ if (pn->pn_head) {
178
+ /* XXX check for dup recycles in the list */
179
+ *pn->pn_tail = tc->nodeList;
180
+ tc->nodeList = pn->pn_head;
181
+ #ifdef METER_PARSENODES
182
+ recyclednodes += pn->pn_count;
183
+ #endif
184
+ }
185
+ break;
186
+ case PN_TERNARY:
187
+ RecycleTree(pn->pn_kid1, tc);
188
+ RecycleTree(pn->pn_kid2, tc);
189
+ RecycleTree(pn->pn_kid3, tc);
190
+ break;
191
+ case PN_BINARY:
192
+ RecycleTree(pn->pn_left, tc);
193
+ RecycleTree(pn->pn_right, tc);
194
+ break;
195
+ case PN_UNARY:
196
+ RecycleTree(pn->pn_kid, tc);
197
+ break;
198
+ case PN_NAME:
199
+ RecycleTree(pn->pn_expr, tc);
200
+ break;
201
+ case PN_NULLARY:
202
+ break;
203
+ }
204
+ }
205
+ return pn;
206
+ }
207
+
208
+ /*
209
+ * Allocate a JSParseNode from cx's temporary arena.
210
+ */
211
+ static JSParseNode *
212
+ NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity,
213
+ JSTreeContext *tc)
214
+ {
215
+ JSParseNode *pn;
216
+
217
+ pn = NewOrRecycledNode(cx, tc);
218
+ if (!pn)
219
+ return NULL;
220
+ pn->pn_type = tok->type;
221
+ pn->pn_pos = tok->pos;
222
+ pn->pn_op = JSOP_NOP;
223
+ pn->pn_arity = arity;
224
+ pn->pn_next = NULL;
225
+ #ifdef METER_PARSENODES
226
+ parsenodes++;
227
+ if (parsenodes - recyclednodes > maxparsenodes)
228
+ maxparsenodes = parsenodes - recyclednodes;
229
+ #endif
230
+ return pn;
231
+ }
232
+
233
+ static JSParseNode *
234
+ NewBinary(JSContext *cx, JSTokenType tt,
235
+ JSOp op, JSParseNode *left, JSParseNode *right,
236
+ JSTreeContext *tc)
237
+ {
238
+ JSParseNode *pn, *pn1, *pn2;
239
+
240
+ if (!left || !right)
241
+ return NULL;
242
+
243
+ /*
244
+ * Flatten a left-associative (left-heavy) tree of a given operator into
245
+ * a list, to reduce js_FoldConstants and js_EmitTree recursion.
246
+ */
247
+ if (left->pn_type == tt &&
248
+ left->pn_op == op &&
249
+ (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
250
+ if (left->pn_arity != PN_LIST) {
251
+ pn1 = left->pn_left, pn2 = left->pn_right;
252
+ left->pn_arity = PN_LIST;
253
+ PN_INIT_LIST_1(left, pn1);
254
+ PN_APPEND(left, pn2);
255
+ left->pn_extra = 0;
256
+ if (tt == TOK_PLUS) {
257
+ if (pn1->pn_type == TOK_STRING)
258
+ left->pn_extra |= PNX_STRCAT;
259
+ else if (pn1->pn_type != TOK_NUMBER)
260
+ left->pn_extra |= PNX_CANTFOLD;
261
+ if (pn2->pn_type == TOK_STRING)
262
+ left->pn_extra |= PNX_STRCAT;
263
+ else if (pn2->pn_type != TOK_NUMBER)
264
+ left->pn_extra |= PNX_CANTFOLD;
265
+ }
266
+ }
267
+ PN_APPEND(left, right);
268
+ left->pn_pos.end = right->pn_pos.end;
269
+ if (tt == TOK_PLUS) {
270
+ if (right->pn_type == TOK_STRING)
271
+ left->pn_extra |= PNX_STRCAT;
272
+ else if (right->pn_type != TOK_NUMBER)
273
+ left->pn_extra |= PNX_CANTFOLD;
274
+ }
275
+ return left;
276
+ }
277
+
278
+ /*
279
+ * Fold constant addition immediately, to conserve node space and, what's
280
+ * more, so js_FoldConstants never sees mixed addition and concatenation
281
+ * operations with more than one leading non-string operand in a PN_LIST
282
+ * generated for expressions such as 1 + 2 + "pt" (which should evaluate
283
+ * to "3pt", not "12pt").
284
+ */
285
+ if (tt == TOK_PLUS &&
286
+ left->pn_type == TOK_NUMBER &&
287
+ right->pn_type == TOK_NUMBER) {
288
+ left->pn_dval += right->pn_dval;
289
+ left->pn_pos.end = right->pn_pos.end;
290
+ RecycleTree(right, tc);
291
+ return left;
292
+ }
293
+
294
+ pn = NewOrRecycledNode(cx, tc);
295
+ if (!pn)
296
+ return NULL;
297
+ pn->pn_type = tt;
298
+ pn->pn_pos.begin = left->pn_pos.begin;
299
+ pn->pn_pos.end = right->pn_pos.end;
300
+ pn->pn_op = op;
301
+ pn->pn_arity = PN_BINARY;
302
+ pn->pn_left = left;
303
+ pn->pn_right = right;
304
+ pn->pn_next = NULL;
305
+ #ifdef METER_PARSENODES
306
+ parsenodes++;
307
+ if (parsenodes - recyclednodes > maxparsenodes)
308
+ maxparsenodes = parsenodes - recyclednodes;
309
+ #endif
310
+ return pn;
311
+ }
312
+
313
+ #if JS_HAS_GETTER_SETTER
314
+ static JSTokenType
315
+ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
316
+ {
317
+ JSAtom *atom;
318
+ JSRuntime *rt;
319
+ JSOp op;
320
+ const char *name;
321
+
322
+ JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME);
323
+ atom = CURRENT_TOKEN(ts).t_atom;
324
+ rt = cx->runtime;
325
+ if (atom == rt->atomState.getterAtom)
326
+ op = JSOP_GETTER;
327
+ else if (atom == rt->atomState.setterAtom)
328
+ op = JSOP_SETTER;
329
+ else
330
+ return TOK_NAME;
331
+ if (js_PeekTokenSameLine(cx, ts) != tt)
332
+ return TOK_NAME;
333
+ (void) js_GetToken(cx, ts);
334
+ if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
335
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
336
+ JSMSG_BAD_GETTER_OR_SETTER,
337
+ (op == JSOP_GETTER)
338
+ ? js_getter_str
339
+ : js_setter_str);
340
+ return TOK_ERROR;
341
+ }
342
+ CURRENT_TOKEN(ts).t_op = op;
343
+ name = js_AtomToPrintableString(cx, atom);
344
+ if (!name ||
345
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
346
+ JSREPORT_WARNING |
347
+ JSREPORT_STRICT,
348
+ JSMSG_DEPRECATED_USAGE,
349
+ name)) {
350
+ return TOK_ERROR;
351
+ }
352
+ return tt;
353
+ }
354
+ #endif
355
+
356
+ /*
357
+ * Parse a top-level JS script.
358
+ */
359
+ JS_FRIEND_API(JSParseNode *)
360
+ js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts)
361
+ {
362
+ JSStackFrame *fp, frame;
363
+ JSTreeContext tc;
364
+ JSParseNode *pn;
365
+
366
+ /*
367
+ * Push a compiler frame if we have no frames, or if the top frame is a
368
+ * lightweight function activation, or if its scope chain doesn't match
369
+ * the one passed to us.
370
+ */
371
+ fp = cx->fp;
372
+ if (!fp || !fp->varobj || fp->scopeChain != chain) {
373
+ memset(&frame, 0, sizeof frame);
374
+ frame.varobj = frame.scopeChain = chain;
375
+ if (cx->options & JSOPTION_VAROBJFIX) {
376
+ while ((chain = JS_GetParent(cx, chain)) != NULL)
377
+ frame.varobj = chain;
378
+ }
379
+ frame.down = fp;
380
+ cx->fp = &frame;
381
+ }
382
+
383
+ /*
384
+ * Protect atoms from being collected by a GC activation, which might
385
+ * - nest on this thread due to out of memory (the so-called "last ditch"
386
+ * GC attempted within js_AllocGCThing), or
387
+ * - run for any reason on another thread if this thread is suspended on
388
+ * an object lock before it finishes generating bytecode into a script
389
+ * protected from the GC by a root or a stack frame reference.
390
+ */
391
+ JS_KEEP_ATOMS(cx->runtime);
392
+ TREE_CONTEXT_INIT(&tc);
393
+ pn = Statements(cx, ts, &tc);
394
+ if (pn) {
395
+ if (!js_MatchToken(cx, ts, TOK_EOF)) {
396
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
397
+ JSMSG_SYNTAX_ERROR);
398
+ pn = NULL;
399
+ } else {
400
+ pn->pn_type = TOK_LC;
401
+ if (!js_FoldConstants(cx, pn, &tc))
402
+ pn = NULL;
403
+ }
404
+ }
405
+
406
+ TREE_CONTEXT_FINISH(&tc);
407
+ JS_UNKEEP_ATOMS(cx->runtime);
408
+ cx->fp = fp;
409
+ return pn;
410
+ }
411
+
412
+ static JSBool
413
+ FindLintIdentifier(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp, jsval *val)
414
+ {
415
+ *objp = NULL;
416
+ *propp = NULL;
417
+
418
+ if (cx->lint && cx->lint->scriptIdentifiers &&
419
+ !OBJ_LOOKUP_PROPERTY(cx, cx->lint->scriptIdentifiers, id, objp, propp)) {
420
+ return JS_FALSE;
421
+ }
422
+ if (*objp) {
423
+ if (val && !OBJ_GET_PROPERTY(cx, cx->lint->scriptIdentifiers, id, val))
424
+ return JS_FALSE;
425
+ return JS_TRUE;
426
+ }
427
+
428
+ if (cx->lint && cx->lint->dependencyList) {
429
+ JSLObjectList *cur = (JSLObjectList*)JS_LIST_HEAD(&cx->lint->dependencyList->links);
430
+ while (cur != cx->lint->dependencyList) {
431
+ /* look up property in dependency */
432
+ if (!OBJ_LOOKUP_PROPERTY(cx, cur->obj, id, objp, propp))
433
+ return JS_FALSE;
434
+ if (*objp) {
435
+ if (val && !OBJ_GET_PROPERTY(cx, cx->lint->scriptIdentifiers, id, val))
436
+ return JS_FALSE;
437
+ return JS_TRUE;
438
+ }
439
+ cur = (JSLObjectList*)JS_NEXT_LINK(&cur->links);
440
+ }
441
+ }
442
+
443
+ return JS_TRUE;
444
+ }
445
+
446
+ static JSBool
447
+ MarkIfDeclared(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode *pn)
448
+ {
449
+ JSAtomListElement *ale;
450
+ JSAtom *atom;
451
+ JSObject *obj, *pobj;
452
+ JSScopeProperty *sprop;
453
+ JSObject *scope;
454
+ JSTreeContext *curtc;
455
+ JSStackFrame *curframe;
456
+ JSStmtInfo *curstmt;
457
+
458
+ atom = pn->pn_atom;
459
+ scope = cx->fp->scopeChain;
460
+
461
+ /* nasty, but undeclared identifiers aren't warned against until end */
462
+ if (SHOULD_IGNORE_LINT_WARNINGS(cx)) {
463
+ pn->pn_attrs |= JSPROP_LINT_IGNORE;
464
+ return JS_TRUE;
465
+ }
466
+
467
+ /* must ignore all variables within "with" blocks */
468
+ curstmt = tc->topStmt;
469
+ while (curstmt) {
470
+ if (curstmt->type == STMT_WITH) {
471
+ pn->pn_attrs |= JSPROP_LINT_IGNORE;
472
+ return JS_TRUE;
473
+ }
474
+ curstmt = curstmt->down;
475
+ }
476
+
477
+ if (scope) {
478
+ /* Find the topmost object in the scope chain. */
479
+ do {
480
+ obj = scope;
481
+ scope = OBJ_GET_PARENT(cx, obj);
482
+ } while (scope);
483
+ } else {
484
+ obj = cx->globalObject;
485
+ }
486
+
487
+ if (obj && !OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, (JSProperty**)&sprop))
488
+ return JS_FALSE;
489
+ if (pobj)
490
+ goto success;
491
+
492
+ curframe = cx->fp;
493
+ while (curframe) {
494
+ if (!OBJ_LOOKUP_PROPERTY(cx, curframe->varobj, (jsid)atom, &pobj, (JSProperty**)&sprop))
495
+ return JS_FALSE;
496
+ if (pobj)
497
+ goto success;
498
+ curframe = curframe->down;
499
+ }
500
+
501
+ curtc = tc;
502
+ while (curtc) {
503
+ ATOM_LIST_SEARCH(ale, &curtc->decls, atom);
504
+ if (ale)
505
+ goto success;
506
+ curtc = curtc->down;
507
+ }
508
+
509
+ curstmt = tc->topStmt;
510
+ while (curstmt) {
511
+ if (curstmt->label && curstmt->label == atom)
512
+ goto success;
513
+ curstmt = curstmt->down;
514
+ }
515
+
516
+ if (js_PeekToken(cx, ts) == TOK_COLON) {
517
+ /* assume that it's a label, which is actually a declaration */
518
+ goto success;
519
+ }
520
+
521
+ /* check for previous identifier */
522
+ if (!FindLintIdentifier(cx, (jsid)atom, &pobj, (JSProperty**)&sprop, NULL)) {
523
+ return JS_FALSE;
524
+ }
525
+ if (pobj)
526
+ goto success;
527
+
528
+ return JS_TRUE;
529
+
530
+ success:
531
+ pn->pn_attrs |= JSPROP_LINT_DECLARED;
532
+ return JS_TRUE;
533
+ }
534
+
535
+ static JSBool
536
+ WarnUndeclaredIdentifiers(JSCodeGenerator *cg, JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
537
+ JSParseNode *pn, JSParseNode *parentNode, JSParseNode *grandParentNode)
538
+ {
539
+ JSParseNode *pn2;
540
+
541
+ if (!pn)
542
+ return JS_TRUE;
543
+
544
+ if (pn->pn_type == TOK_NAME && (pn->pn_attrs & JSPROP_LINT_IGNORE) == 0 && (pn->pn_attrs & JSPROP_LINT_DECLARED) == 0) {
545
+ if (!MarkIfDeclared(cx, ts, tc, pn))
546
+ return JS_FALSE;
547
+
548
+ if ((pn->pn_attrs & JSPROP_LINT_DECLARED) == 0) {
549
+ /* hack : temporarily change current line for error reporting */
550
+ JSBool res;
551
+ uintN start = CG_CURRENT_LINE(cg);
552
+ const char *name = js_AtomToPrintableString(cx, pn->pn_atom);
553
+
554
+ CG_CURRENT_LINE(cg) = pn->pn_pos.begin.lineno;
555
+ res = js_ReportCompileErrorNumber(cx, NULL, cg,
556
+ JSREPORT_WARNING |
557
+ JSREPORT_STRICT,
558
+ JSMSG_UNDECLARED_IDENTIFIER,
559
+ name);
560
+ CG_CURRENT_LINE(cg) = start;
561
+
562
+ if (!res)
563
+ return JS_FALSE;
564
+ }
565
+ }
566
+
567
+ switch (pn->pn_arity) {
568
+ case PN_LIST:
569
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
570
+ if (!WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn2, pn, parentNode)) {
571
+ return JS_FALSE;
572
+ }
573
+ }
574
+ return JS_TRUE;
575
+ case PN_TERNARY:
576
+ return WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_kid1, pn, parentNode) &&
577
+ WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_kid2, pn, parentNode) &&
578
+ WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_kid3, pn, parentNode);
579
+ case PN_BINARY:
580
+ return WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_left, pn, parentNode) &&
581
+ WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_right, pn, parentNode);
582
+ case PN_UNARY:
583
+ return WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_kid, pn, parentNode);
584
+ case PN_NAME:
585
+ return WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_expr, pn, parentNode);
586
+ case PN_FUNC:
587
+ return WarnUndeclaredIdentifiers(cg, cx, ts, tc, pn->pn_body, pn, parentNode);
588
+ default:
589
+ return JS_TRUE;
590
+ }
591
+ }
592
+
593
+ static JSBool
594
+ MarkDeclaredIdentifiers(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode *pn,
595
+ JSParseNode *parentNode, JSParseNode *grandParentNode)
596
+ {
597
+ JSParseNode *pn2;
598
+
599
+ if (!pn)
600
+ return JS_TRUE;
601
+
602
+ if (pn->pn_type == TOK_NAME) {
603
+ if (SHOULD_IGNORE_LINT_WARNINGS(cx)) {
604
+ /* nasty, but undeclared identifiers aren't warned against until end */
605
+ pn->pn_attrs |= JSPROP_LINT_IGNORE;
606
+ }
607
+ else if ((pn->pn_attrs & JSPROP_LINT_DECLARED) == 0) {
608
+ JSTreeContext *curtc;
609
+ JSAtomListElement *ale;
610
+
611
+ curtc = tc;
612
+ while (curtc) {
613
+ ATOM_LIST_SEARCH(ale, &curtc->decls, pn->pn_atom);
614
+ if (ale) {
615
+ pn->pn_attrs |= JSPROP_LINT_DECLARED;
616
+ break;
617
+ }
618
+ curtc = curtc->down;
619
+ }
620
+ }
621
+ }
622
+
623
+ switch (pn->pn_arity) {
624
+ case PN_LIST:
625
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
626
+ if (!MarkDeclaredIdentifiers(cx, ts, tc, pn2, pn, parentNode)) {
627
+ return JS_FALSE;
628
+ }
629
+ }
630
+ return JS_TRUE;
631
+ case PN_TERNARY:
632
+ return MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_kid1, pn, parentNode) &&
633
+ MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_kid2, pn, parentNode) &&
634
+ MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_kid3, pn, parentNode);
635
+ case PN_BINARY:
636
+ return MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_left, pn, parentNode) &&
637
+ MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_right, pn, parentNode);
638
+ case PN_UNARY:
639
+ return MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_kid, pn, parentNode);
640
+ case PN_NAME:
641
+ return MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_expr, pn, parentNode);
642
+ case PN_FUNC:
643
+ return MarkDeclaredIdentifiers(cx, ts, tc, pn->pn_body, pn, parentNode);
644
+ default:
645
+ return JS_TRUE;
646
+ }
647
+ }
648
+
649
+ /*
650
+ * Compile a top-level script.
651
+ */
652
+ JS_FRIEND_API(JSBool)
653
+ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
654
+ JSCodeGenerator *cg)
655
+ {
656
+ JSStackFrame *fp, frame;
657
+ uint32 flags;
658
+ JSParseNode *pn;
659
+ JSBool ok;
660
+ #ifdef METER_PARSENODES
661
+ void *sbrk(ptrdiff_t), *before = sbrk(0);
662
+ #endif
663
+
664
+ /*
665
+ * Push a compiler frame if we have no frames, or if the top frame is a
666
+ * lightweight function activation, or if its scope chain doesn't match
667
+ * the one passed to us.
668
+ */
669
+ fp = cx->fp;
670
+ if (!fp || !fp->varobj || fp->scopeChain != chain) {
671
+ memset(&frame, 0, sizeof frame);
672
+ frame.varobj = frame.scopeChain = chain;
673
+ if (cx->options & JSOPTION_VAROBJFIX) {
674
+ while ((chain = JS_GetParent(cx, chain)) != NULL)
675
+ frame.varobj = chain;
676
+ }
677
+ frame.down = fp;
678
+ cx->fp = &frame;
679
+ }
680
+ flags = cx->fp->flags;
681
+ cx->fp->flags = flags |
682
+ (JS_HAS_COMPILE_N_GO_OPTION(cx)
683
+ ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
684
+ : JSFRAME_COMPILING);
685
+
686
+ /* Prevent GC activation while compiling. */
687
+ JS_KEEP_ATOMS(cx->runtime);
688
+
689
+ pn = Statements(cx, ts, &cg->treeContext);
690
+ if (!pn) {
691
+ ok = JS_FALSE;
692
+ } else if (!js_MatchToken(cx, ts, TOK_EOF)) {
693
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
694
+ JSMSG_SYNTAX_ERROR);
695
+ ok = JS_FALSE;
696
+ } else {
697
+ #ifdef METER_PARSENODES
698
+ printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
699
+ (char *)sbrk(0) - (char *)before,
700
+ parsenodes,
701
+ maxparsenodes,
702
+ parsenodes - recyclednodes);
703
+ before = sbrk(0);
704
+ #endif
705
+
706
+ /*
707
+ * No need to emit code here -- Statements already has, for each
708
+ * statement in turn. Search for TCF_COMPILING in Statements, below.
709
+ * That flag is set for every tc == &cg->treeContext, and it implies
710
+ * that the tc can be downcast to a cg and used to emit code during
711
+ * parsing, rather than at the end of the parse phase.
712
+ */
713
+ JS_ASSERT(cg->treeContext.flags & TCF_COMPILING);
714
+ ok = JS_TRUE;
715
+ }
716
+
717
+ if (cx->lint) {
718
+ if (ok && cx->lint->controlCommentsIgnore &&
719
+ !js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING, JSMSG_MISMATCH_CTRL_COMMENTS)) {
720
+ ok = JS_FALSE;
721
+ }
722
+ /* forcibly turn off ignore so undeclared identifier warnings are displayed */
723
+ cx->lint->controlCommentsIgnore = JS_FALSE;
724
+
725
+ /*
726
+ * Two files may have import directives pointing to each other. All import directives
727
+ * must be processed after the entire script has been examined to allow such files to
728
+ * recognize each other's identifiers.
729
+ */
730
+ if (cx->lint->importPaths) {
731
+ while (!JS_CLIST_IS_EMPTY(&cx->lint->importPaths->links)) {
732
+ JSLImportPathList *curPath;
733
+ curPath = (JSLImportPathList*)JS_LIST_HEAD(&cx->lint->importPaths->links);
734
+ JS_REMOVE_LINK(&curPath->links);
735
+
736
+ if (cx->lint->importCallback)
737
+ cx->lint->importCallback(cx, curPath->importPath, cx->lint->importCallbackParms);
738
+
739
+ JS_free(cx, curPath->importPath);
740
+ JS_free(cx, curPath);
741
+ }
742
+ }
743
+
744
+ if (ok) {
745
+ if (cx->lint->alwaysUseOptionExplicit || cx->lint->controlCommentsOptionExplicit) {
746
+ /* warn against undeclared identifiers */
747
+ if (!WarnUndeclaredIdentifiers(cg, cx, ts, &cg->treeContext, pn, NULL, NULL))
748
+ ok = JS_FALSE;
749
+ }
750
+ else if (!cx->lint->hasCompletedPartialScript) {
751
+ /* warn about missing "option explicit" (but only once) */
752
+ if (!js_ReportCompileErrorNumber(cx, ts, cg, JSREPORT_WARNING, JSMSG_MISSING_OPTION_EXPLICIT))
753
+ ok = JS_FALSE;
754
+ }
755
+ }
756
+
757
+ cx->lint->hasCompletedPartialScript = JS_TRUE;
758
+ }
759
+
760
+ #ifdef METER_PARSENODES
761
+ printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n",
762
+ (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount);
763
+ #endif
764
+ #ifdef JS_ARENAMETER
765
+ JS_DumpArenaStats(stdout);
766
+ #endif
767
+ JS_UNKEEP_ATOMS(cx->runtime);
768
+ cx->fp->flags = flags;
769
+ cx->fp = fp;
770
+ return ok;
771
+ }
772
+
773
+ /*
774
+ * Insist on a final return before control flows out of pn, but don't be too
775
+ * smart about loops (do {...; return e2;} while(0) at the end of a function
776
+ * that contains an early return e1 will get a strict-option-only warning).
777
+ */
778
+ #define ENDS_IN_OTHER 0
779
+ #define ENDS_IN_RETURN 1
780
+ #define ENDS_IN_BREAK 2
781
+
782
+ static int
783
+ HasFinalReturn(JSParseNode *pn, JSBool breakIsReturn)
784
+ {
785
+ /* jsl: the break statement should be treated the same as a return for lint purposes (breakIsReturn) */
786
+ uintN rv, rv2, hasDefault;
787
+ JSParseNode *pn2, *pn3;
788
+
789
+ switch (pn->pn_type) {
790
+ case TOK_LC:
791
+ if (!pn->pn_head)
792
+ return ENDS_IN_OTHER;
793
+ return HasFinalReturn(PN_LAST(pn), breakIsReturn);
794
+
795
+ case TOK_IF:
796
+ rv = HasFinalReturn(pn->pn_kid2, breakIsReturn);
797
+ if (pn->pn_kid3)
798
+ rv &= HasFinalReturn(pn->pn_kid3, breakIsReturn);
799
+ return rv;
800
+
801
+ #if JS_HAS_SWITCH_STATEMENT
802
+ case TOK_SWITCH:
803
+ rv = ENDS_IN_RETURN;
804
+ hasDefault = ENDS_IN_OTHER;
805
+ for (pn2 = pn->pn_kid2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
806
+ if (pn2->pn_type == TOK_DEFAULT)
807
+ hasDefault = ENDS_IN_RETURN;
808
+ pn3 = pn2->pn_right;
809
+ JS_ASSERT(pn3->pn_type == TOK_LC);
810
+ if (pn3->pn_head) {
811
+ rv2 = HasFinalReturn(PN_LAST(pn3), breakIsReturn);
812
+ if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
813
+ /* Falling through to next case or default. */;
814
+ else
815
+ rv &= rv2;
816
+ }
817
+ }
818
+ /* If a final switch has no default case, we judge it harshly. */
819
+ rv &= hasDefault;
820
+ return rv;
821
+ #endif /* JS_HAS_SWITCH_STATEMENT */
822
+
823
+ case TOK_BREAK:
824
+ if (breakIsReturn)
825
+ return ENDS_IN_RETURN;
826
+ else
827
+ return ENDS_IN_BREAK;
828
+
829
+ case TOK_WITH:
830
+ return HasFinalReturn(pn->pn_right, breakIsReturn);
831
+
832
+ case TOK_RETURN:
833
+ return ENDS_IN_RETURN;
834
+
835
+ #if JS_HAS_EXCEPTIONS
836
+ case TOK_THROW:
837
+ return ENDS_IN_RETURN;
838
+
839
+ case TOK_TRY:
840
+ /* If we have a finally block that returns, we are done. */
841
+ if (pn->pn_kid3) {
842
+ rv = HasFinalReturn(pn->pn_kid3, breakIsReturn);
843
+ if (rv == ENDS_IN_RETURN)
844
+ return rv;
845
+ }
846
+
847
+ /* Else check the try block and any and all catch statements. */
848
+ rv = HasFinalReturn(pn->pn_kid1, breakIsReturn);
849
+ if (pn->pn_kid2)
850
+ rv &= HasFinalReturn(pn->pn_kid2, breakIsReturn);
851
+ return rv;
852
+
853
+ case TOK_CATCH:
854
+ /* Check this block's code and iterate over further catch blocks. */
855
+ rv = HasFinalReturn(pn->pn_kid3, breakIsReturn);
856
+ for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)
857
+ rv &= HasFinalReturn(pn2->pn_kid3, breakIsReturn);
858
+ return rv;
859
+ #endif
860
+
861
+ default:
862
+ return ENDS_IN_OTHER;
863
+ }
864
+ }
865
+
866
+ static JSBool
867
+ ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
868
+ {
869
+ JSFunction *fun;
870
+ JSBool ok;
871
+
872
+ fun = cx->fp->fun;
873
+ if (fun->atom) {
874
+ char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));
875
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
876
+ JSREPORT_WARNING |
877
+ JSREPORT_STRICT,
878
+ JSMSG_NO_RETURN_VALUE, name);
879
+ } else {
880
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
881
+ JSREPORT_WARNING |
882
+ JSREPORT_STRICT,
883
+ JSMSG_ANON_NO_RETURN_VALUE);
884
+ }
885
+ return ok;
886
+ }
887
+
888
+ static JSBool
889
+ CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
890
+ {
891
+ return HasFinalReturn(pn, JS_FALSE) == ENDS_IN_RETURN || ReportNoReturnValue(cx, ts);
892
+ }
893
+
894
+ static JSParseNode *
895
+ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
896
+ JSTreeContext *tc)
897
+ {
898
+ JSStackFrame *fp, frame;
899
+ JSObject *funobj;
900
+ uintN oldflags;
901
+ JSParseNode *pn;
902
+
903
+ fp = cx->fp;
904
+ funobj = fun->object;
905
+ if (!fp || fp->fun != fun || fp->varobj != funobj ||
906
+ fp->scopeChain != funobj) {
907
+ memset(&frame, 0, sizeof frame);
908
+ frame.fun = fun;
909
+ frame.varobj = frame.scopeChain = funobj;
910
+ frame.down = fp;
911
+ frame.flags = (fp->flags & JSFRAME_COMPILE_N_GO);
912
+ cx->fp = &frame;
913
+ }
914
+
915
+ oldflags = tc->flags;
916
+ tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
917
+ tc->flags |= TCF_IN_FUNCTION;
918
+ pn = Statements(cx, ts, tc);
919
+
920
+ /* Check for falling off the end of a function that returns a value. */
921
+ if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
922
+ if (!CheckFinalReturn(cx, ts, pn))
923
+ pn = NULL;
924
+ }
925
+
926
+ cx->fp = fp;
927
+ /* pass thru return value information for lint */
928
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS) | (cx->lint ? (tc->flags & TCF_RETURN_EXPR) : 0);
929
+ return pn;
930
+ }
931
+
932
+ /*
933
+ * Compile a JS function body, which might appear as the value of an event
934
+ * handler attribute in an HTML <INPUT> tag.
935
+ */
936
+ JSBool
937
+ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
938
+ {
939
+ JSArenaPool codePool, notePool;
940
+ JSCodeGenerator funcg;
941
+ JSStackFrame *fp, frame;
942
+ JSObject *funobj;
943
+ JSParseNode *pn;
944
+ JSBool ok;
945
+
946
+ JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
947
+ JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
948
+ if (!js_InitCodeGenerator(cx, &funcg, &codePool, &notePool,
949
+ ts->filename, ts->lineno,
950
+ ts->principals)) {
951
+ return JS_FALSE;
952
+ }
953
+
954
+ /* Prevent GC activation while compiling. */
955
+ JS_KEEP_ATOMS(cx->runtime);
956
+
957
+ /* Push a JSStackFrame for use by FunctionBody. */
958
+ fp = cx->fp;
959
+ funobj = fun->object;
960
+ JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
961
+ fp->scopeChain != funobj));
962
+ memset(&frame, 0, sizeof frame);
963
+ frame.fun = fun;
964
+ frame.varobj = frame.scopeChain = funobj;
965
+ frame.down = fp;
966
+ frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx)
967
+ ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
968
+ : JSFRAME_COMPILING;
969
+ cx->fp = &frame;
970
+
971
+ /* Ensure that the body looks like a block statement to js_EmitTree. */
972
+ CURRENT_TOKEN(ts).type = TOK_LC;
973
+ pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
974
+ if (!pn) {
975
+ ok = JS_FALSE;
976
+ } else {
977
+ /*
978
+ * No need to emit code here -- Statements (via FunctionBody) already
979
+ * has. See similar comment in js_CompileTokenStream, and bug 108257.
980
+ */
981
+ fun->u.script = js_NewScriptFromCG(cx, &funcg, fun);
982
+ if (!fun->u.script) {
983
+ ok = JS_FALSE;
984
+ } else {
985
+ fun->interpreted = JS_TRUE;
986
+ if (funcg.treeContext.flags & TCF_FUN_HEAVYWEIGHT)
987
+ fun->flags |= JSFUN_HEAVYWEIGHT;
988
+ ok = JS_TRUE;
989
+ }
990
+ }
991
+
992
+ /* Restore saved state and release code generation arenas. */
993
+ cx->fp = fp;
994
+ JS_UNKEEP_ATOMS(cx->runtime);
995
+ js_FinishCodeGenerator(cx, &funcg);
996
+ JS_FinishArenaPool(&codePool);
997
+ JS_FinishArenaPool(&notePool);
998
+ return ok;
999
+ }
1000
+
1001
+ static JSParseNode *
1002
+ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
1003
+ JSBool lambda)
1004
+ {
1005
+ JSOp op, prevop;
1006
+ JSParseNode *pn, *body;
1007
+ JSAtom *funAtom, *argAtom;
1008
+ JSStackFrame *fp;
1009
+ JSObject *varobj, *pobj;
1010
+ JSAtomListElement *ale;
1011
+ JSProperty *prop;
1012
+ JSFunction *fun;
1013
+ uintN dupflag;
1014
+ JSBool ok;
1015
+ JSTreeContext funtc;
1016
+
1017
+ /* Make a TOK_FUNCTION node. */
1018
+ #if JS_HAS_GETTER_SETTER
1019
+ op = CURRENT_TOKEN(ts).t_op;
1020
+ #endif
1021
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
1022
+ if (!pn)
1023
+ return NULL;
1024
+
1025
+ /* Scan the optional function name into funAtom. */
1026
+ funAtom = js_MatchToken(cx, ts, TOK_NAME) ? CURRENT_TOKEN(ts).t_atom : NULL;
1027
+
1028
+ if (cx->lint && cx->lint->enableJScriptFunctionExtensions) {
1029
+ /* match multiple dot sequences */
1030
+ while (js_MatchToken(cx, ts, TOK_DOT)) {
1031
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_SYNTAX_ERROR);
1032
+ funAtom = NULL;
1033
+ }
1034
+
1035
+ /* match double-colon syntax */
1036
+ if (js_MatchToken(cx, ts, TOK_COLON)) {
1037
+ MUST_MATCH_TOKEN(TOK_COLON, JSMSG_SYNTAX_ERROR);
1038
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_SYNTAX_ERROR);
1039
+ funAtom = NULL;
1040
+ }
1041
+ }
1042
+
1043
+ /* Find the nearest variable-declaring scope and use it as our parent. */
1044
+ fp = cx->fp;
1045
+ varobj = fp->varobj;
1046
+
1047
+ /*
1048
+ * Record names for function statements in tc->decls so we know when to
1049
+ * avoid optimizing variable references that might name a function.
1050
+ */
1051
+ if (!lambda && funAtom) {
1052
+ ATOM_LIST_SEARCH(ale, &tc->decls, funAtom);
1053
+ if (ale) {
1054
+ prevop = ALE_JSOP(ale);
1055
+ if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {
1056
+ const char *name = js_AtomToPrintableString(cx, funAtom);
1057
+ if (!name ||
1058
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
1059
+ (prevop != JSOP_DEFCONST)
1060
+ ? JSREPORT_WARNING |
1061
+ JSREPORT_STRICT
1062
+ : JSREPORT_ERROR,
1063
+ JSMSG_REDECLARED_VAR,
1064
+ (prevop == JSOP_DEFFUN ||
1065
+ prevop == JSOP_CLOSURE)
1066
+ ? js_function_str
1067
+ : (prevop == JSOP_DEFCONST)
1068
+ ? js_const_str
1069
+ : js_var_str,
1070
+ name)) {
1071
+ return NULL;
1072
+ }
1073
+ }
1074
+ if (tc->topStmt && prevop == JSOP_DEFVAR)
1075
+ tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
1076
+ } else {
1077
+ /* save global identifier for lint */
1078
+ if (cx->lint && cx->lint->scriptIdentifiers && !tc->down) {
1079
+ jsval val;
1080
+ val = INT_TO_JSVAL(0);
1081
+ if (!js_SetProperty(cx, cx->lint->scriptIdentifiers, (jsid)funAtom, &val))
1082
+ return NULL;
1083
+ }
1084
+ ale = js_IndexAtom(cx, funAtom, &tc->decls);
1085
+ if (!ale)
1086
+ return NULL;
1087
+ }
1088
+ ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);
1089
+
1090
+ #if JS_HAS_LEXICAL_CLOSURE
1091
+ /*
1092
+ * A function nested at top level inside another's body needs only a
1093
+ * local variable to bind its name to its value, and not an activation
1094
+ * object property (it might also need the activation property, if the
1095
+ * outer function contains with statements, e.g., but the stack slot
1096
+ * wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
1097
+ * JSOP_GETVAR bytecode).
1098
+ */
1099
+ if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {
1100
+ /*
1101
+ * Define a property on the outer function so that LookupArgOrVar
1102
+ * can properly optimize accesses.
1103
+ *
1104
+ * XXX Here and in Variables, we use the function object's scope,
1105
+ * XXX arguably polluting it, when we could use a compiler-private
1106
+ * XXX scope structure. Tradition!
1107
+ */
1108
+ JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
1109
+ JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
1110
+ if (!js_LookupProperty(cx, varobj, (jsid)funAtom, &pobj, &prop))
1111
+ return NULL;
1112
+ if (prop)
1113
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
1114
+ if (!prop || pobj != varobj) {
1115
+ if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom,
1116
+ JSVAL_VOID,
1117
+ js_GetLocalVariable,
1118
+ js_SetLocalVariable,
1119
+ JSPROP_ENUMERATE | JSPROP_SHARED,
1120
+ SPROP_HAS_SHORTID, fp->fun->nvars,
1121
+ NULL)) {
1122
+ return NULL;
1123
+ }
1124
+ fp->fun->nvars++;
1125
+ }
1126
+ }
1127
+ #endif
1128
+ }
1129
+
1130
+ fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj,
1131
+ funAtom);
1132
+ if (!fun)
1133
+ return NULL;
1134
+ #if JS_HAS_GETTER_SETTER
1135
+ if (op != JSOP_NOP)
1136
+ fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
1137
+ #endif
1138
+
1139
+ /* Now parse formal argument list and compute fun->nargs. */
1140
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
1141
+ if (!js_MatchToken(cx, ts, TOK_RP)) {
1142
+ do {
1143
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);
1144
+ argAtom = CURRENT_TOKEN(ts).t_atom;
1145
+ pobj = NULL;
1146
+ if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
1147
+ &prop)) {
1148
+ return NULL;
1149
+ }
1150
+ dupflag = 0;
1151
+ if (prop) {
1152
+ ok = JS_TRUE;
1153
+ if (pobj == fun->object &&
1154
+ ((JSScopeProperty *) prop)->getter == js_GetArgument) {
1155
+ const char *name = js_AtomToPrintableString(cx, argAtom);
1156
+
1157
+ /*
1158
+ * A duplicate parameter name. We force a duplicate node
1159
+ * on the SCOPE_LAST_PROP(scope) list with the same id,
1160
+ * distinguished by the SPROP_IS_DUPLICATE flag, and not
1161
+ * mapped by an entry in scope.
1162
+ */
1163
+ ok = name &&
1164
+ js_ReportCompileErrorNumber(cx, ts, NULL,
1165
+ JSREPORT_WARNING |
1166
+ JSREPORT_STRICT,
1167
+ JSMSG_DUPLICATE_FORMAL,
1168
+ name);
1169
+
1170
+ dupflag = SPROP_IS_DUPLICATE;
1171
+ }
1172
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
1173
+ if (!ok)
1174
+ return NULL;
1175
+ prop = NULL;
1176
+ }
1177
+ if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
1178
+ js_GetArgument, js_SetArgument,
1179
+ SPROP_INVALID_SLOT,
1180
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
1181
+ JSPROP_SHARED,
1182
+ SPROP_HAS_SHORTID | dupflag,
1183
+ fun->nargs)) {
1184
+ return NULL;
1185
+ }
1186
+ fun->nargs++;
1187
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
1188
+
1189
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);
1190
+ }
1191
+
1192
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
1193
+ pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
1194
+
1195
+ TREE_CONTEXT_INIT(&funtc);
1196
+ funtc.down = tc;
1197
+ body = FunctionBody(cx, ts, fun, &funtc);
1198
+ if (!body)
1199
+ return NULL;
1200
+
1201
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
1202
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
1203
+
1204
+ #if JS_HAS_LEXICAL_CLOSURE
1205
+ /*
1206
+ * If we collected flags that indicate nested heavyweight functions, or
1207
+ * this function contains heavyweight-making statements (references to
1208
+ * __parent__ or __proto__; use of with, eval, import, or export; and
1209
+ * assignment to arguments), flag the function as heavyweight (requiring
1210
+ * a call object per invocation).
1211
+ */
1212
+ if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {
1213
+ fun->flags |= JSFUN_HEAVYWEIGHT;
1214
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
1215
+ } else {
1216
+ /*
1217
+ * If this function is a named statement function not at top-level
1218
+ * (i.e. a JSOP_CLOSURE), or if it refers to unqualified names that
1219
+ * are not local args or vars (TCF_FUN_USES_NONLOCALS), then our
1220
+ * enclosing function, if any, must be heavyweight.
1221
+ */
1222
+ if ((!lambda && funAtom && tc->topStmt) ||
1223
+ (funtc.flags & TCF_FUN_USES_NONLOCALS)) {
1224
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
1225
+ }
1226
+ }
1227
+ #endif
1228
+
1229
+ #if JS_HAS_LEXICAL_CLOSURE
1230
+ if (lambda || !funAtom) {
1231
+ /*
1232
+ * ECMA ed. 3 standard: function expression, possibly anonymous (even
1233
+ * if at top-level, an unnamed function is an expression statement, not
1234
+ * a function declaration).
1235
+ */
1236
+ op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
1237
+ } else if (tc->topStmt) {
1238
+ /*
1239
+ * ECMA ed. 3 extension: a function expression statement not at the
1240
+ * top level, e.g., in a compound statement such as the "then" part
1241
+ * of an "if" statement, binds a closure only if control reaches that
1242
+ * sub-statement.
1243
+ */
1244
+ op = JSOP_CLOSURE;
1245
+ } else
1246
+ #endif
1247
+ op = JSOP_NOP;
1248
+
1249
+ /*
1250
+ * Absent use of the new scoped local GC roots API around compiler calls,
1251
+ * we need to atomize here to protect against a GC activation. Atoms are
1252
+ * protected from GC during compilation by the JS_FRIEND_API entry points
1253
+ * in this file. There doesn't seem to be any gain in switching from the
1254
+ * atom-keeping method to the bulkier, slower scoped local roots method.
1255
+ */
1256
+ pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);
1257
+ if (!pn->pn_funAtom)
1258
+ return NULL;
1259
+
1260
+ pn->pn_op = op;
1261
+ pn->pn_body = body;
1262
+ pn->pn_flags = funtc.flags & TCF_FUN_FLAGS;
1263
+ pn->pn_tryCount = funtc.tryCount;
1264
+ TREE_CONTEXT_FINISH(&funtc);
1265
+
1266
+ /* Flag declared identifiers before this goes out of scope */
1267
+ if (cx->lint)
1268
+ MarkDeclaredIdentifiers(cx, ts, &funtc, pn, NULL, NULL);
1269
+
1270
+ return pn;
1271
+ }
1272
+
1273
+ static JSParseNode *
1274
+ FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1275
+ {
1276
+ return FunctionDef(cx, ts, tc, JS_FALSE);
1277
+ }
1278
+
1279
+ #if JS_HAS_LEXICAL_CLOSURE
1280
+ static JSParseNode *
1281
+ FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1282
+ {
1283
+ return FunctionDef(cx, ts, tc, JS_TRUE);
1284
+ }
1285
+ #endif
1286
+
1287
+ static JSBool
1288
+ isIncDec(JSParseNode *pn)
1289
+ {
1290
+ return pn && pn->pn_arity == PN_UNARY &&
1291
+ (pn->pn_type == TOK_INC || pn->pn_type == TOK_DEC);
1292
+ }
1293
+
1294
+ static JSBool
1295
+ hasIncDec(JSParseNode *pn)
1296
+ {
1297
+ JSParseNode *pn2;
1298
+
1299
+ if (!pn)
1300
+ return JS_FALSE;
1301
+
1302
+ if (isIncDec(pn))
1303
+ return JS_TRUE;
1304
+
1305
+ switch (pn->pn_arity) {
1306
+ case PN_LIST:
1307
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
1308
+ if (pn->pn_type == TOK_COMMA && isIncDec(pn2))
1309
+ continue;
1310
+ if (hasIncDec(pn2))
1311
+ return JS_TRUE;
1312
+ }
1313
+ return JS_FALSE;
1314
+ case PN_TERNARY:
1315
+ return hasIncDec(pn->pn_kid1) ||
1316
+ hasIncDec(pn->pn_kid2) ||
1317
+ hasIncDec(pn->pn_kid3);
1318
+ case PN_BINARY:
1319
+ return hasIncDec(pn->pn_left) || hasIncDec(pn->pn_right);
1320
+ case PN_UNARY:
1321
+ return hasIncDec(pn->pn_kid);
1322
+ case PN_NAME:
1323
+ return hasIncDec(pn->pn_expr);
1324
+ default:
1325
+ return JS_FALSE;
1326
+ }
1327
+ }
1328
+
1329
+ static JSBool
1330
+ warnIfHasIncDec(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
1331
+ {
1332
+ if (!hasIncDec(pn))
1333
+ return JS_TRUE;
1334
+
1335
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1336
+ JSREPORT_WARNING |
1337
+ JSREPORT_STRICT,
1338
+ JSMSG_INC_DEC_WITHIN_STMT)) {
1339
+ return JS_FALSE;
1340
+ }
1341
+
1342
+ return JS_TRUE;
1343
+ }
1344
+
1345
+ /*
1346
+ * Parse the statements in a block, creating a TOK_LC node that lists the
1347
+ * statements' trees. If called from block-parsing code, the caller must
1348
+ * match { before and } after.
1349
+ */
1350
+ static JSParseNode *
1351
+ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1352
+ {
1353
+ JSParseNode *pn, *pn2;
1354
+ JSTokenType tt;
1355
+ JSBool hadtoken, foundPass;
1356
+ JSBool beyondreach, alreadywarnedunreachable;
1357
+
1358
+ CHECK_RECURSION();
1359
+
1360
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
1361
+ if (!pn)
1362
+ return NULL;
1363
+ PN_INIT_LIST(pn);
1364
+
1365
+ ts->flags |= TSF_OPERAND;
1366
+ hadtoken = JS_FALSE;
1367
+ foundPass = JS_FALSE;
1368
+ beyondreach = JS_FALSE;
1369
+ alreadywarnedunreachable = JS_FALSE;
1370
+
1371
+ /* Check for the "pass" keyword when the next token is scanned.
1372
+ */
1373
+ if (cx->lint && tc->topStmt) {
1374
+ cx->lint->controlCommentsAllowPass = JS_TRUE;
1375
+ cx->lint->controlCommentsFoundPass = JS_FALSE;
1376
+ tt = js_PeekToken(cx, ts);
1377
+ foundPass = cx->lint->controlCommentsFoundPass;
1378
+ cx->lint->controlCommentsAllowPass = JS_FALSE;
1379
+ cx->lint->controlCommentsFoundPass = JS_FALSE;
1380
+ }
1381
+
1382
+ while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
1383
+ if (beyondreach && !alreadywarnedunreachable) {
1384
+ alreadywarnedunreachable = JS_TRUE;
1385
+ if (cx->lint && !js_ReportCompileErrorNumber(cx, ts, NULL,
1386
+ JSREPORT_WARNING |
1387
+ JSREPORT_STRICT,
1388
+ JSMSG_UNREACHABLE_CODE)) {
1389
+ return NULL;
1390
+ }
1391
+ }
1392
+
1393
+ if (foundPass && !js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING, JSMSG_INVALID_PASS))
1394
+ return NULL;
1395
+
1396
+ hadtoken = JS_TRUE;
1397
+ beyondreach = (beyondreach || tt == TOK_BREAK || tt == TOK_CONTINUE || tt == TOK_RETURN || tt == TOK_THROW);
1398
+ ts->flags &= ~TSF_OPERAND;
1399
+ pn2 = Statement(cx, ts, tc);
1400
+ if (!pn2)
1401
+ return NULL;
1402
+
1403
+ ts->flags |= TSF_OPERAND;
1404
+
1405
+ /*
1406
+ * If compiling top-level statements, emit as we go to save space,
1407
+ * except when linting (so we can check for undeclared identifiers)
1408
+ */
1409
+ if (!tc->topStmt && (tc->flags & TCF_COMPILING) && !cx->lint) {
1410
+ if (cx->fp->fun &&
1411
+ JS_HAS_STRICT_OPTION(cx) &&
1412
+ (tc->flags & TCF_RETURN_EXPR)) {
1413
+ /*
1414
+ * Check pn2 for lack of a final return statement if it is the
1415
+ * last statement in the block.
1416
+ */
1417
+ tt = js_PeekToken(cx, ts);
1418
+ if ((tt == TOK_EOF || tt == TOK_RC) &&
1419
+ !CheckFinalReturn(cx, ts, pn2)) {
1420
+ tt = TOK_ERROR;
1421
+ break;
1422
+ }
1423
+
1424
+ /*
1425
+ * Clear TCF_RETURN_EXPR so FunctionBody doesn't try to
1426
+ * CheckFinalReturn again.
1427
+ */
1428
+ tc->flags &= ~TCF_RETURN_EXPR;
1429
+ }
1430
+ if (!js_FoldConstants(cx, pn2, tc) ||
1431
+ !js_AllocTryNotes(cx, (JSCodeGenerator *)tc) ||
1432
+ !js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) {
1433
+ tt = TOK_ERROR;
1434
+ break;
1435
+ }
1436
+ RecycleTree(pn2, tc);
1437
+ } else {
1438
+ PN_APPEND(pn, pn2);
1439
+ }
1440
+ }
1441
+ ts->flags &= ~TSF_OPERAND;
1442
+ if (tt == TOK_ERROR)
1443
+ return NULL;
1444
+
1445
+ /* empty catch is useful */
1446
+ if (cx->lint && !hadtoken && !foundPass && tc->topStmt && tc->topStmt->type != STMT_CATCH) {
1447
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1448
+ JSREPORT_WARNING | JSREPORT_STRICT,
1449
+ JSMSG_EMPTY_STATEMENT)) {
1450
+ return NULL;
1451
+ }
1452
+ }
1453
+
1454
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
1455
+ return pn;
1456
+ }
1457
+
1458
+ static JSParseNode *
1459
+ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1460
+ {
1461
+ JSParseNode *pn, *pn2;
1462
+
1463
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
1464
+ pn = Expr(cx, ts, tc);
1465
+ if (!pn)
1466
+ return NULL;
1467
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
1468
+
1469
+ /*
1470
+ * Check for (a = b) and "correct" it to (a == b) iff b's operator has
1471
+ * greater precedence than ==.
1472
+ * XXX not ECMA, but documented in several books -- now a strict warning.
1473
+ */
1474
+ if (pn->pn_type == TOK_ASSIGN &&
1475
+ pn->pn_op == JSOP_NOP &&
1476
+ pn->pn_right->pn_type > TOK_EQOP)
1477
+ {
1478
+ JSBool rewrite = !JSVERSION_IS_ECMA(cx->version);
1479
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1480
+ JSREPORT_WARNING | JSREPORT_STRICT,
1481
+ JSMSG_EQUAL_AS_ASSIGN,
1482
+ rewrite
1483
+ ? "\nAssuming equality test"
1484
+ : "")) {
1485
+ return NULL;
1486
+ }
1487
+ if (rewrite) {
1488
+ pn->pn_type = TOK_EQOP;
1489
+ pn->pn_op = (JSOp)cx->jsop_eq;
1490
+ pn2 = pn->pn_left;
1491
+ switch (pn2->pn_op) {
1492
+ case JSOP_SETNAME:
1493
+ pn2->pn_op = JSOP_NAME;
1494
+ break;
1495
+ case JSOP_SETPROP:
1496
+ pn2->pn_op = JSOP_GETPROP;
1497
+ break;
1498
+ case JSOP_SETELEM:
1499
+ pn2->pn_op = JSOP_GETELEM;
1500
+ break;
1501
+ default:
1502
+ JS_ASSERT(0);
1503
+ }
1504
+ }
1505
+ }
1506
+ return pn;
1507
+ }
1508
+
1509
+ static JSBool
1510
+ MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
1511
+ {
1512
+ JSAtom *label;
1513
+ #if JS_HAS_LABEL_STATEMENT
1514
+ JSTokenType tt;
1515
+
1516
+ tt = js_PeekTokenSameLine(cx, ts);
1517
+ if (tt == TOK_ERROR)
1518
+ return JS_FALSE;
1519
+ if (tt == TOK_NAME) {
1520
+ (void) js_GetToken(cx, ts);
1521
+ label = CURRENT_TOKEN(ts).t_atom;
1522
+ } else {
1523
+ label = NULL;
1524
+ }
1525
+ #else
1526
+ label = NULL;
1527
+ #endif
1528
+ pn->pn_atom = label;
1529
+ return JS_TRUE;
1530
+ }
1531
+
1532
+ #if JS_HAS_EXPORT_IMPORT
1533
+ static JSParseNode *
1534
+ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1535
+ {
1536
+ JSParseNode *pn, *pn2, *pn3;
1537
+ JSTokenType tt;
1538
+
1539
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
1540
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
1541
+ if (!pn)
1542
+ return NULL;
1543
+ pn->pn_op = JSOP_NAME;
1544
+ pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
1545
+ pn->pn_expr = NULL;
1546
+ pn->pn_slot = -1;
1547
+ pn->pn_attrs = 0;
1548
+
1549
+ ts->flags |= TSF_OPERAND;
1550
+ while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) {
1551
+ ts->flags &= ~TSF_OPERAND;
1552
+ if (pn->pn_op == JSOP_IMPORTALL)
1553
+ goto bad_import;
1554
+
1555
+ if (tt == TOK_DOT) {
1556
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
1557
+ if (!pn2)
1558
+ return NULL;
1559
+ if (js_MatchToken(cx, ts, TOK_STAR)) {
1560
+ pn2->pn_op = JSOP_IMPORTALL;
1561
+ pn2->pn_atom = NULL;
1562
+ } else {
1563
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
1564
+ pn2->pn_op = JSOP_GETPROP;
1565
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
1566
+ pn2->pn_slot = -1;
1567
+ pn2->pn_attrs = 0;
1568
+ }
1569
+ pn2->pn_expr = pn;
1570
+ pn2->pn_pos.begin = pn->pn_pos.begin;
1571
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
1572
+ } else {
1573
+ /* Make a TOK_LB node. */
1574
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
1575
+ if (!pn2)
1576
+ return NULL;
1577
+ pn3 = Expr(cx, ts, tc);
1578
+ if (!pn3)
1579
+ return NULL;
1580
+
1581
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
1582
+ pn2->pn_pos.begin = pn->pn_pos.begin;
1583
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
1584
+
1585
+ pn2->pn_op = JSOP_GETELEM;
1586
+ pn2->pn_left = pn;
1587
+ pn2->pn_right = pn3;
1588
+ }
1589
+
1590
+ pn = pn2;
1591
+ ts->flags |= TSF_OPERAND;
1592
+ }
1593
+ ts->flags &= ~TSF_OPERAND;
1594
+ if (tt == TOK_ERROR)
1595
+ return NULL;
1596
+ js_UngetToken(ts);
1597
+
1598
+ switch (pn->pn_op) {
1599
+ case JSOP_GETPROP:
1600
+ pn->pn_op = JSOP_IMPORTPROP;
1601
+ break;
1602
+ case JSOP_GETELEM:
1603
+ pn->pn_op = JSOP_IMPORTELEM;
1604
+ break;
1605
+ case JSOP_IMPORTALL:
1606
+ break;
1607
+ default:
1608
+ goto bad_import;
1609
+ }
1610
+ return pn;
1611
+
1612
+ bad_import:
1613
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_IMPORT);
1614
+ return NULL;
1615
+ }
1616
+ #endif /* JS_HAS_EXPORT_IMPORT */
1617
+
1618
+ extern const char js_with_statement_str[];
1619
+
1620
+ static JSBool
1621
+ AreExpressionsIdentical(JSContext *cx, JSParseNode *pn1, JSParseNode *pn2, JSBool functionsAreIdentical)
1622
+ {
1623
+ JSParseNode *child1, *child2;
1624
+
1625
+ if (!pn1 && !pn2)
1626
+ return JS_TRUE;
1627
+ else if (!pn1 || !pn2)
1628
+ return JS_FALSE;
1629
+
1630
+ /* check types */
1631
+ if (pn1->pn_type != pn2->pn_type)
1632
+ return JS_FALSE;
1633
+ if (pn1->pn_op != pn2->pn_op)
1634
+ return JS_FALSE;
1635
+ if (pn1->pn_arity != pn2->pn_arity)
1636
+ return JS_FALSE;
1637
+
1638
+ /* bail out with function */
1639
+ if (!functionsAreIdentical) {
1640
+ if (pn1->pn_type == TOK_FUNCTION)
1641
+ return JS_FALSE;
1642
+ else if (pn1->pn_type == TOK_LP && pn1->pn_op == JSOP_CALL)
1643
+ return JS_FALSE;
1644
+ }
1645
+
1646
+ /* check atoms on names, properties, and string constants */
1647
+ if (pn1->pn_type == TOK_NAME ||
1648
+ pn1->pn_type == TOK_DOT ||
1649
+ pn1->pn_type == TOK_STRING) {
1650
+ if (pn1->pn_atom != pn2->pn_atom)
1651
+ return JS_FALSE;
1652
+ }
1653
+
1654
+ /* check values on numbers */
1655
+ if (pn1->pn_type == TOK_NUMBER)
1656
+ {
1657
+ if (pn1->pn_dval != pn2->pn_dval)
1658
+ return JS_FALSE;
1659
+ }
1660
+
1661
+ switch (pn1->pn_arity) {
1662
+ case PN_LIST:
1663
+ if (pn1->pn_count != pn2->pn_count)
1664
+ return JS_FALSE;
1665
+ for (child1 = pn1->pn_head, child2 = pn2->pn_head; child1 && child2;
1666
+ child1 = child1->pn_next, child2 = child2->pn_next) {
1667
+
1668
+ if (!AreExpressionsIdentical(cx, child1, child2, functionsAreIdentical)) {
1669
+ return JS_FALSE;
1670
+ }
1671
+ }
1672
+ return JS_TRUE;
1673
+ case PN_TERNARY:
1674
+ return AreExpressionsIdentical(cx, pn1->pn_kid1, pn2->pn_kid1, functionsAreIdentical) &&
1675
+ AreExpressionsIdentical(cx, pn1->pn_kid2, pn2->pn_kid2, functionsAreIdentical) &&
1676
+ AreExpressionsIdentical(cx, pn1->pn_kid3, pn2->pn_kid3, functionsAreIdentical);
1677
+ case PN_BINARY:
1678
+ return AreExpressionsIdentical(cx, pn1->pn_left, pn2->pn_left, functionsAreIdentical) &&
1679
+ AreExpressionsIdentical(cx, pn1->pn_right, pn2->pn_right, functionsAreIdentical);
1680
+ case PN_UNARY:
1681
+ return AreExpressionsIdentical(cx, pn1->pn_kid, pn2->pn_kid, functionsAreIdentical);
1682
+ case PN_NAME:
1683
+ return AreExpressionsIdentical(cx, pn1->pn_expr, pn2->pn_expr, functionsAreIdentical);
1684
+ case PN_FUNC:
1685
+ return AreExpressionsIdentical(cx, pn1->pn_body, pn2->pn_body, functionsAreIdentical);
1686
+ default:
1687
+ return JS_TRUE;
1688
+ }
1689
+ }
1690
+
1691
+ static JSParseNode *
1692
+ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
1693
+ {
1694
+ JSTokenType tt;
1695
+ JSParseNode *pn, *pn1, *pn2, *pn3, *pn4;
1696
+ JSStmtInfo stmtInfo, *stmt, *stmt2;
1697
+ JSAtom *label;
1698
+
1699
+ CHECK_RECURSION();
1700
+
1701
+ if (cx->lint && tc->topStmt && tc->topStmt->type == STMT_ELSE) {
1702
+ /*
1703
+ * check for an else statement that could be matched against multiple if statements
1704
+ * (go up the statement stack looking for an if statement until a block statement is hit)
1705
+ */
1706
+ JSStmtInfo *curStmt = tc->topStmt->down;
1707
+ while (curStmt && curStmt->type != STMT_BLOCK && curStmt->type != STMT_TRY &&
1708
+ curStmt->type != STMT_CATCH && curStmt->type != STMT_FINALLY) {
1709
+ if (curStmt->type == STMT_IF) {
1710
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1711
+ JSREPORT_WARNING | JSREPORT_STRICT,
1712
+ JSMSG_AMBIGUOUS_ELSE_STMT)) {
1713
+ return NULL;
1714
+ }
1715
+ break;
1716
+ }
1717
+ curStmt = curStmt->down;
1718
+ }
1719
+ }
1720
+
1721
+ ts->flags |= TSF_OPERAND;
1722
+ tt = js_GetToken(cx, ts);
1723
+ ts->flags &= ~TSF_OPERAND;
1724
+
1725
+ if (cx->lint && tt != TOK_LC && tc->topStmt &&
1726
+ !(tc->topStmt->type == STMT_ELSE && tt == TOK_IF)/* allow else if statements */) {
1727
+ switch (tc->topStmt->type) {
1728
+ case STMT_BLOCK:
1729
+ case STMT_LABEL:
1730
+ case STMT_SWITCH:
1731
+ case STMT_SUBROUTINE:
1732
+ /* ignore */
1733
+ break;
1734
+
1735
+ case STMT_TRY:
1736
+ case STMT_CATCH:
1737
+ case STMT_FINALLY:
1738
+ /* syntax always requires curly */
1739
+ break;
1740
+
1741
+ case STMT_IF:
1742
+ case STMT_ELSE:
1743
+ case STMT_WITH:
1744
+ case STMT_DO_LOOP:
1745
+ case STMT_FOR_LOOP:
1746
+ case STMT_FOR_IN_LOOP:
1747
+ case STMT_WHILE_LOOP:
1748
+ if (tt == TOK_IF || tt == TOK_WHILE || tt == TOK_DO || tt == TOK_FOR || tt == TOK_WITH) {
1749
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1750
+ JSREPORT_WARNING |
1751
+ JSREPORT_STRICT,
1752
+ JSMSG_AMBIGUOUS_NESTED_STMT)) {
1753
+ return NULL;
1754
+ }
1755
+ }
1756
+ else if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1757
+ JSREPORT_WARNING |
1758
+ JSREPORT_STRICT,
1759
+ JSMSG_BLOCK_WITHOUT_BRACES)) {
1760
+ return NULL;
1761
+ }
1762
+ }
1763
+ }
1764
+
1765
+ #if JS_HAS_GETTER_SETTER
1766
+ if (tt == TOK_NAME) {
1767
+ tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
1768
+ if (tt == TOK_ERROR)
1769
+ return NULL;
1770
+ }
1771
+ #endif
1772
+
1773
+ switch (tt) {
1774
+ #if JS_HAS_EXPORT_IMPORT
1775
+ case TOK_EXPORT:
1776
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
1777
+ if (!pn)
1778
+ return NULL;
1779
+ PN_INIT_LIST(pn);
1780
+ if (js_MatchToken(cx, ts, TOK_STAR)) {
1781
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
1782
+ if (!pn2)
1783
+ return NULL;
1784
+ PN_APPEND(pn, pn2);
1785
+ } else {
1786
+ do {
1787
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME);
1788
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
1789
+ if (!pn2)
1790
+ return NULL;
1791
+ pn2->pn_op = JSOP_NAME;
1792
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
1793
+ pn2->pn_expr = NULL;
1794
+ pn2->pn_slot = -1;
1795
+ pn2->pn_attrs = 0;
1796
+ PN_APPEND(pn, pn2);
1797
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
1798
+ }
1799
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
1800
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
1801
+ break;
1802
+
1803
+ case TOK_IMPORT:
1804
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
1805
+ if (!pn)
1806
+ return NULL;
1807
+ PN_INIT_LIST(pn);
1808
+ do {
1809
+ pn2 = ImportExpr(cx, ts, tc);
1810
+ if (!pn2)
1811
+ return NULL;
1812
+ PN_APPEND(pn, pn2);
1813
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
1814
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
1815
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
1816
+ break;
1817
+ #endif /* JS_HAS_EXPORT_IMPORT */
1818
+
1819
+ case TOK_FUNCTION:
1820
+ return FunctionStmt(cx, ts, tc);
1821
+
1822
+ case TOK_IF:
1823
+ /* An IF node has three kids: condition, then, and optional else. */
1824
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
1825
+ if (!pn)
1826
+ return NULL;
1827
+ pn1 = Condition(cx, ts, tc);
1828
+ if (!pn1)
1829
+ return NULL;
1830
+ js_PushStatement(tc, &stmtInfo, STMT_IF, -1);
1831
+ pn2 = Statement(cx, ts, tc);
1832
+ if (!pn2)
1833
+ return NULL;
1834
+ if (js_MatchToken(cx, ts, TOK_ELSE)) {
1835
+ stmtInfo.type = STMT_ELSE;
1836
+ pn3 = Statement(cx, ts, tc);
1837
+ if (!pn3)
1838
+ return NULL;
1839
+ pn->pn_pos.end = pn3->pn_pos.end;
1840
+ } else {
1841
+ pn3 = NULL;
1842
+ pn->pn_pos.end = pn2->pn_pos.end;
1843
+ }
1844
+ js_PopStatement(tc);
1845
+ pn->pn_kid1 = pn1;
1846
+ pn->pn_kid2 = pn2;
1847
+ pn->pn_kid3 = pn3;
1848
+ return pn;
1849
+
1850
+ #if JS_HAS_SWITCH_STATEMENT
1851
+ case TOK_SWITCH:
1852
+ {
1853
+ JSParseNode *pn5;
1854
+ JSBool seenDefault = JS_FALSE;
1855
+
1856
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
1857
+ if (!pn)
1858
+ return NULL;
1859
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
1860
+
1861
+ /* pn1 points to the switch's discriminant. */
1862
+ pn1 = Expr(cx, ts, tc);
1863
+ if (!pn1)
1864
+ return NULL;
1865
+
1866
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
1867
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
1868
+
1869
+ /* pn2 is a list of case nodes. The default case has pn_left == NULL */
1870
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
1871
+ if (!pn2)
1872
+ return NULL;
1873
+ PN_INIT_LIST(pn2);
1874
+
1875
+ js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
1876
+
1877
+ while ((tt = js_GetToken(cx, ts)) != TOK_RC) {
1878
+ switch (tt) {
1879
+ case TOK_DEFAULT:
1880
+ if (seenDefault) {
1881
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
1882
+ JSMSG_TOO_MANY_DEFAULTS);
1883
+ return NULL;
1884
+ }
1885
+ seenDefault = JS_TRUE;
1886
+ /* fall through */
1887
+
1888
+ case TOK_CASE:
1889
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
1890
+ if (!pn3)
1891
+ return NULL;
1892
+ if (tt == TOK_DEFAULT) {
1893
+ pn3->pn_left = NULL;
1894
+ } else {
1895
+ pn3->pn_left = Expr(cx, ts, tc);
1896
+ if (!pn3->pn_left)
1897
+ return NULL;
1898
+
1899
+ /* check for duplicate case statements */
1900
+ for (pn5 = pn2->pn_head; pn5; pn5 = pn5->pn_next) {
1901
+ /* assume that function calls are identical */
1902
+ if (AreExpressionsIdentical(cx, pn5->pn_left, pn3->pn_left, JS_TRUE)) {
1903
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT,
1904
+ JSMSG_DUPLICATE_CASE_IN_SWITCH)) {
1905
+ return NULL;
1906
+ }
1907
+ break;
1908
+ }
1909
+ }
1910
+ }
1911
+ PN_APPEND(pn2, pn3);
1912
+ if (pn2->pn_count == JS_BIT(16)) {
1913
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
1914
+ JSMSG_TOO_MANY_CASES);
1915
+ return NULL;
1916
+ }
1917
+ break;
1918
+
1919
+ case TOK_ERROR:
1920
+ return NULL;
1921
+
1922
+ default:
1923
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
1924
+ JSMSG_BAD_SWITCH);
1925
+ return NULL;
1926
+ }
1927
+ MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
1928
+
1929
+ pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
1930
+ if (!pn4)
1931
+ return NULL;
1932
+ pn4->pn_type = TOK_LC;
1933
+ PN_INIT_LIST(pn4);
1934
+
1935
+ if (cx->lint) {
1936
+ /* must allow fallthru before peeking */
1937
+ cx->lint->controlCommentsAllowFallthru = JS_TRUE;
1938
+ cx->lint->controlCommentsHadFallthru = JS_FALSE;
1939
+ }
1940
+
1941
+ while ((tt = js_PeekToken(cx, ts)) != TOK_RC &&
1942
+ tt != TOK_CASE && tt != TOK_DEFAULT) {
1943
+ if (tt == TOK_ERROR)
1944
+ return NULL;
1945
+
1946
+ pn5 = Statement(cx, ts, tc);
1947
+ if (!pn5)
1948
+ return NULL;
1949
+
1950
+ pn4->pn_pos.end = pn5->pn_pos.end;
1951
+ PN_APPEND(pn4, pn5);
1952
+ }
1953
+
1954
+ if (cx->lint) {
1955
+ cx->lint->controlCommentsAllowFallthru = JS_FALSE;
1956
+
1957
+ if (pn3->pn_type == TOK_DEFAULT && tt != TOK_RC &&
1958
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
1959
+ JSREPORT_WARNING | JSREPORT_STRICT,
1960
+ JSMSG_DEFAULT_NOT_AT_END)) {
1961
+ return NULL;
1962
+ }
1963
+
1964
+ if (pn4->pn_head) {
1965
+ if (HasFinalReturn(PN_LAST(pn4), JS_TRUE) == ENDS_IN_OTHER) {
1966
+ /* must have fallthru or return/break statement on non-empty case */
1967
+ if (!cx->lint->controlCommentsHadFallthru &&
1968
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
1969
+ JSREPORT_WARNING | JSREPORT_STRICT,
1970
+ (tt == TOK_RC) ? JSMSG_MISSING_BREAK_FOR_LAST_CASE : JSMSG_MISSING_BREAK)) {
1971
+ return NULL;
1972
+ }
1973
+ }
1974
+ else if (cx->lint->controlCommentsHadFallthru &&
1975
+ !js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING, JSMSG_INVALID_FALLTHRU)) {
1976
+ /* fallthru does nothing here */
1977
+ return NULL;
1978
+ }
1979
+ }
1980
+ else if (tt == TOK_RC && !cx->lint->controlCommentsHadFallthru) {
1981
+ /* the last statement must have a break */
1982
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
1983
+ JSREPORT_WARNING | JSREPORT_STRICT,
1984
+ JSMSG_MISSING_BREAK_FOR_LAST_CASE)) {
1985
+ return NULL;
1986
+ }
1987
+ }
1988
+ }
1989
+
1990
+ /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */
1991
+ if (pn4->pn_head)
1992
+ pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin;
1993
+ pn3->pn_pos.end = pn4->pn_pos.end;
1994
+ pn3->pn_right = pn4;
1995
+ }
1996
+
1997
+ if (!seenDefault && !js_ReportCompileErrorNumber(cx, ts, NULL,
1998
+ JSREPORT_WARNING | JSREPORT_STRICT,
1999
+ JSMSG_MISSING_DEFAULT_CASE)) {
2000
+ return NULL;
2001
+ }
2002
+
2003
+ js_PopStatement(tc);
2004
+
2005
+ pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
2006
+ pn->pn_kid1 = pn1;
2007
+ pn->pn_kid2 = pn2;
2008
+ return pn;
2009
+ }
2010
+ #endif /* JS_HAS_SWITCH_STATEMENT */
2011
+
2012
+ case TOK_WHILE:
2013
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
2014
+ if (!pn)
2015
+ return NULL;
2016
+ js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
2017
+ pn2 = Condition(cx, ts, tc);
2018
+ if (!pn2)
2019
+ return NULL;
2020
+ pn->pn_left = pn2;
2021
+ pn2 = Statement(cx, ts, tc);
2022
+ if (!pn2)
2023
+ return NULL;
2024
+ js_PopStatement(tc);
2025
+ pn->pn_pos.end = pn2->pn_pos.end;
2026
+ pn->pn_right = pn2;
2027
+ return pn;
2028
+
2029
+ #if JS_HAS_DO_WHILE_LOOP
2030
+ case TOK_DO:
2031
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
2032
+ if (!pn)
2033
+ return NULL;
2034
+ js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
2035
+ pn2 = Statement(cx, ts, tc);
2036
+ if (!pn2)
2037
+ return NULL;
2038
+ pn->pn_left = pn2;
2039
+ MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
2040
+ pn2 = Condition(cx, ts, tc);
2041
+ if (!pn2)
2042
+ return NULL;
2043
+ js_PopStatement(tc);
2044
+ pn->pn_pos.end = pn2->pn_pos.end;
2045
+ pn->pn_right = pn2;
2046
+ if (cx->version != JSVERSION_ECMA_3) {
2047
+ /*
2048
+ * All legacy and extended versions must do automatic semicolon
2049
+ * insertion after do-while. See the testcase and discussion in
2050
+ * http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
2051
+ */
2052
+ (void) js_MatchToken(cx, ts, TOK_SEMI);
2053
+ return pn;
2054
+ }
2055
+ break;
2056
+ #endif /* JS_HAS_DO_WHILE_LOOP */
2057
+
2058
+ case TOK_FOR:
2059
+ /* A FOR node is binary, left is loop control and right is the body. */
2060
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
2061
+ if (!pn)
2062
+ return NULL;
2063
+ js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
2064
+
2065
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
2066
+ ts->flags |= TSF_OPERAND;
2067
+ tt = js_PeekToken(cx, ts);
2068
+ ts->flags &= ~TSF_OPERAND;
2069
+ if (tt == TOK_SEMI) {
2070
+ /* No initializer -- set first kid of left sub-node to null. */
2071
+ pn1 = NULL;
2072
+ } else {
2073
+ /* Set pn1 to a var list or an initializing expression. */
2074
+ #if JS_HAS_IN_OPERATOR
2075
+ /*
2076
+ * Set the TCF_IN_FOR_INIT flag during parsing of the first clause
2077
+ * of the for statement. This flag will be used by the RelExpr
2078
+ * production; if it is set, then the 'in' keyword will not be
2079
+ * recognized as an operator, leaving it available to be parsed as
2080
+ * part of a for/in loop. A side effect of this restriction is
2081
+ * that (unparenthesized) expressions involving an 'in' operator
2082
+ * are illegal in the init clause of an ordinary for loop.
2083
+ */
2084
+ tc->flags |= TCF_IN_FOR_INIT;
2085
+ #endif /* JS_HAS_IN_OPERATOR */
2086
+ if (tt == TOK_VAR) {
2087
+ (void) js_GetToken(cx, ts);
2088
+ pn1 = Variables(cx, ts, tc);
2089
+ } else {
2090
+ pn1 = Expr(cx, ts, tc);
2091
+ }
2092
+ #if JS_HAS_IN_OPERATOR
2093
+ tc->flags &= ~TCF_IN_FOR_INIT;
2094
+ #endif /* JS_HAS_IN_OPERATOR */
2095
+ if (!pn1)
2096
+ return NULL;
2097
+ }
2098
+
2099
+ /*
2100
+ * We can be sure that it's a for/in loop if there's still an 'in'
2101
+ * keyword here, even if JavaScript recognizes 'in' as an operator,
2102
+ * as we've excluded 'in' from being parsed in RelExpr by setting
2103
+ * the TCF_IN_FOR_INIT flag in our JSTreeContext.
2104
+ */
2105
+ if (pn1 && js_MatchToken(cx, ts, TOK_IN)) {
2106
+ stmtInfo.type = STMT_FOR_IN_LOOP;
2107
+
2108
+ /* Check that the left side of the 'in' is valid. */
2109
+ if ((pn1->pn_type == TOK_VAR)
2110
+ ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST)
2111
+ : (pn1->pn_type != TOK_NAME &&
2112
+ pn1->pn_type != TOK_DOT &&
2113
+ pn1->pn_type != TOK_LB)) {
2114
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2115
+ JSMSG_BAD_FOR_LEFTSIDE);
2116
+ return NULL;
2117
+ }
2118
+
2119
+ if (pn1->pn_type == TOK_VAR) {
2120
+ /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */
2121
+ pn1->pn_extra |= PNX_FORINVAR;
2122
+
2123
+ /* Generate a final POP only if the var has an initializer. */
2124
+ pn2 = pn1->pn_head;
2125
+ if (pn2->pn_expr)
2126
+ pn1->pn_extra |= PNX_POPVAR;
2127
+ } else {
2128
+ pn2 = pn1;
2129
+ }
2130
+
2131
+ /* Beware 'for (arguments in ...)' with or without a 'var'. */
2132
+ if (pn2->pn_type == TOK_NAME &&
2133
+ pn2->pn_atom == cx->runtime->atomState.argumentsAtom) {
2134
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
2135
+ }
2136
+
2137
+ /* Parse the object expression as the right operand of 'in'. */
2138
+ pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc), tc);
2139
+ if (!pn2)
2140
+ return NULL;
2141
+ pn->pn_left = pn2;
2142
+ } else {
2143
+ /* Parse the loop condition or null into pn2. */
2144
+ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
2145
+ ts->flags |= TSF_OPERAND;
2146
+ tt = js_PeekToken(cx, ts);
2147
+ ts->flags &= ~TSF_OPERAND;
2148
+ if (tt == TOK_SEMI) {
2149
+ pn2 = NULL;
2150
+ } else {
2151
+ pn2 = Expr(cx, ts, tc);
2152
+ if (!pn2)
2153
+ return NULL;
2154
+ }
2155
+
2156
+ /* Parse the update expression or null into pn3. */
2157
+ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
2158
+ ts->flags |= TSF_OPERAND;
2159
+ tt = js_PeekToken(cx, ts);
2160
+ ts->flags &= ~TSF_OPERAND;
2161
+ if (tt == TOK_RP) {
2162
+ pn3 = NULL;
2163
+ } else {
2164
+ tc->flags |= TCF_IN_FOR_POST;
2165
+ if (cx->lint)
2166
+ cx->lint->allowIncDec = JS_TRUE;
2167
+ pn3 = Expr(cx, ts, tc);
2168
+ if (cx->lint) {
2169
+ cx->lint->allowIncDec = JS_FALSE;
2170
+ if (!isIncDec(pn3) && !warnIfHasIncDec(cx, ts, pn3))
2171
+ return NULL;
2172
+ }
2173
+ tc->flags &= ~TCF_IN_FOR_POST;
2174
+ if (!pn3)
2175
+ return NULL;
2176
+ }
2177
+
2178
+ /* Build the RESERVED node to use as the left kid of pn. */
2179
+ pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
2180
+ if (!pn4)
2181
+ return NULL;
2182
+ pn4->pn_type = TOK_RESERVED;
2183
+ pn4->pn_op = JSOP_NOP;
2184
+ pn4->pn_kid1 = pn1;
2185
+ pn4->pn_kid2 = pn2;
2186
+ pn4->pn_kid3 = pn3;
2187
+ pn->pn_left = pn4;
2188
+ }
2189
+
2190
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
2191
+
2192
+ /* Parse the loop body into pn->pn_right. */
2193
+ pn2 = Statement(cx, ts, tc);
2194
+ if (!pn2)
2195
+ return NULL;
2196
+ pn->pn_right = pn2;
2197
+ js_PopStatement(tc);
2198
+
2199
+ /* Record the absolute line number for source note emission. */
2200
+ pn->pn_pos.end = pn2->pn_pos.end;
2201
+ return pn;
2202
+
2203
+ #if JS_HAS_EXCEPTIONS
2204
+ case TOK_TRY: {
2205
+ JSParseNode *catchtail = NULL;
2206
+ /*
2207
+ * try nodes are ternary.
2208
+ * kid1 is the try Statement
2209
+ * kid2 is the catch node
2210
+ * kid3 is the finally Statement
2211
+ *
2212
+ * catch nodes are ternary.
2213
+ * kid1 is the discriminant
2214
+ * kid2 is the next catch node, or NULL
2215
+ * kid3 is the catch block (on kid3 so that we can always append a
2216
+ * new catch pn on catchtail->kid2)
2217
+ *
2218
+ * catch discriminant nodes are binary
2219
+ * atom is the receptacle
2220
+ * expr is the discriminant code
2221
+ *
2222
+ * finally nodes are unary (just the finally expression)
2223
+ */
2224
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
2225
+ pn->pn_op = JSOP_NOP;
2226
+
2227
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
2228
+ js_PushStatement(tc, &stmtInfo, STMT_TRY, -1);
2229
+ pn->pn_kid1 = Statements(cx, ts, tc);
2230
+ if (!pn->pn_kid1)
2231
+ return NULL;
2232
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
2233
+ js_PopStatement(tc);
2234
+
2235
+ catchtail = pn;
2236
+ while (js_PeekToken(cx, ts) == TOK_CATCH) {
2237
+ /* check for another catch after unconditional catch */
2238
+ if (catchtail != pn && !catchtail->pn_kid1->pn_expr) {
2239
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2240
+ JSMSG_CATCH_AFTER_GENERAL);
2241
+ return NULL;
2242
+ }
2243
+
2244
+ /*
2245
+ * legal catch forms are:
2246
+ * catch (v)
2247
+ * catch (v if <boolean_expression>)
2248
+ * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
2249
+ */
2250
+ (void) js_GetToken(cx, ts); /* eat `catch' */
2251
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
2252
+ if (!pn2)
2253
+ return NULL;
2254
+
2255
+ /*
2256
+ * We use a PN_NAME for the discriminant (catchguard) node
2257
+ * with the actual discriminant code in the initializer spot
2258
+ */
2259
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
2260
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);
2261
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
2262
+ if (!pn3)
2263
+ return NULL;
2264
+
2265
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
2266
+ pn3->pn_expr = NULL;
2267
+ #if JS_HAS_CATCH_GUARD
2268
+ /*
2269
+ * We use `catch (x if x === 5)' (not `catch (x : x === 5)') to
2270
+ * avoid conflicting with the JS2/ECMA2 proposed catchguard syntax.
2271
+ */
2272
+ if (js_PeekToken(cx, ts) == TOK_IF) {
2273
+ (void)js_GetToken(cx, ts); /* eat `if' */
2274
+ pn3->pn_expr = Expr(cx, ts, tc);
2275
+ if (!pn3->pn_expr)
2276
+ return NULL;
2277
+ }
2278
+ #endif
2279
+ pn3->pn_attrs |= JSPROP_LINT_DECLARED;
2280
+ pn2->pn_kid1 = pn3;
2281
+
2282
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
2283
+
2284
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
2285
+ js_PushStatement(tc, &stmtInfo, STMT_CATCH, -1);
2286
+ stmtInfo.label = pn3->pn_atom;
2287
+ pn2->pn_kid3 = Statements(cx, ts, tc);
2288
+ if (!pn2->pn_kid3)
2289
+ return NULL;
2290
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
2291
+ js_PopStatement(tc);
2292
+
2293
+ catchtail = catchtail->pn_kid2 = pn2;
2294
+ }
2295
+ catchtail->pn_kid2 = NULL;
2296
+
2297
+ if (js_MatchToken(cx, ts, TOK_FINALLY)) {
2298
+ tc->tryCount++;
2299
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
2300
+ js_PushStatement(tc, &stmtInfo, STMT_FINALLY, -1);
2301
+ pn->pn_kid3 = Statements(cx, ts, tc);
2302
+ if (!pn->pn_kid3)
2303
+ return NULL;
2304
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
2305
+ js_PopStatement(tc);
2306
+ } else {
2307
+ pn->pn_kid3 = NULL;
2308
+ }
2309
+ if (!pn->pn_kid2 && !pn->pn_kid3) {
2310
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2311
+ JSMSG_CATCH_OR_FINALLY);
2312
+ return NULL;
2313
+ }
2314
+ tc->tryCount++;
2315
+ return pn;
2316
+ }
2317
+
2318
+ case TOK_THROW:
2319
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
2320
+ if (!pn)
2321
+ return NULL;
2322
+
2323
+ /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
2324
+ ts->flags |= TSF_OPERAND;
2325
+ tt = js_PeekTokenSameLine(cx, ts);
2326
+ ts->flags &= ~TSF_OPERAND;
2327
+ if (tt == TOK_ERROR)
2328
+ return NULL;
2329
+ if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
2330
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2331
+ JSMSG_SYNTAX_ERROR);
2332
+ return NULL;
2333
+ }
2334
+
2335
+ pn2 = Expr(cx, ts, tc);
2336
+ if (!pn2)
2337
+ return NULL;
2338
+ pn->pn_pos.end = pn2->pn_pos.end;
2339
+ pn->pn_op = JSOP_THROW;
2340
+ pn->pn_kid = pn2;
2341
+ break;
2342
+
2343
+ /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
2344
+ case TOK_CATCH:
2345
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2346
+ JSMSG_CATCH_WITHOUT_TRY);
2347
+ return NULL;
2348
+
2349
+ case TOK_FINALLY:
2350
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2351
+ JSMSG_FINALLY_WITHOUT_TRY);
2352
+ return NULL;
2353
+
2354
+ #endif /* JS_HAS_EXCEPTIONS */
2355
+
2356
+ case TOK_BREAK:
2357
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
2358
+ if (!pn)
2359
+ return NULL;
2360
+ if (!MatchLabel(cx, ts, pn))
2361
+ return NULL;
2362
+ stmt = tc->topStmt;
2363
+ label = pn->pn_atom;
2364
+ if (label) {
2365
+ for (; ; stmt = stmt->down) {
2366
+ if (!stmt) {
2367
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2368
+ JSMSG_LABEL_NOT_FOUND);
2369
+ return NULL;
2370
+ }
2371
+ if (stmt->type == STMT_LABEL && stmt->label == label)
2372
+ break;
2373
+ }
2374
+ } else {
2375
+ for (; ; stmt = stmt->down) {
2376
+ if (!stmt) {
2377
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2378
+ JSMSG_TOUGH_BREAK);
2379
+ return NULL;
2380
+ }
2381
+ if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)
2382
+ break;
2383
+ }
2384
+ }
2385
+ if (label)
2386
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
2387
+ break;
2388
+
2389
+ case TOK_CONTINUE:
2390
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
2391
+ if (!pn)
2392
+ return NULL;
2393
+ if (!MatchLabel(cx, ts, pn))
2394
+ return NULL;
2395
+ stmt = tc->topStmt;
2396
+ label = pn->pn_atom;
2397
+ if (label) {
2398
+ for (stmt2 = NULL; ; stmt = stmt->down) {
2399
+ if (!stmt) {
2400
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2401
+ JSMSG_LABEL_NOT_FOUND);
2402
+ return NULL;
2403
+ }
2404
+ if (stmt->type == STMT_LABEL) {
2405
+ if (stmt->label == label) {
2406
+ if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
2407
+ js_ReportCompileErrorNumber(cx, ts, NULL,
2408
+ JSREPORT_ERROR,
2409
+ JSMSG_BAD_CONTINUE);
2410
+ return NULL;
2411
+ }
2412
+ break;
2413
+ }
2414
+ } else {
2415
+ stmt2 = stmt;
2416
+ }
2417
+ }
2418
+ } else {
2419
+ for (; ; stmt = stmt->down) {
2420
+ if (!stmt) {
2421
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2422
+ JSMSG_BAD_CONTINUE);
2423
+ return NULL;
2424
+ }
2425
+ if (STMT_IS_LOOP(stmt))
2426
+ break;
2427
+ }
2428
+ }
2429
+ if (label)
2430
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
2431
+ break;
2432
+
2433
+ case TOK_WITH:
2434
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
2435
+ JSREPORT_WARNING | JSREPORT_STRICT,
2436
+ JSMSG_WITH_STATEMENT)) {
2437
+ return NULL;
2438
+ }
2439
+
2440
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
2441
+ if (!pn)
2442
+ return NULL;
2443
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
2444
+ pn2 = Expr(cx, ts, tc);
2445
+ if (!pn2)
2446
+ return NULL;
2447
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
2448
+ pn->pn_left = pn2;
2449
+
2450
+ js_PushStatement(tc, &stmtInfo, STMT_WITH, -1);
2451
+ pn2 = Statement(cx, ts, tc);
2452
+ if (!pn2)
2453
+ return NULL;
2454
+ js_PopStatement(tc);
2455
+
2456
+ pn->pn_pos.end = pn2->pn_pos.end;
2457
+ pn->pn_right = pn2;
2458
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
2459
+ return pn;
2460
+
2461
+ case TOK_VAR:
2462
+ pn = Variables(cx, ts, tc);
2463
+ if (!pn)
2464
+ return NULL;
2465
+
2466
+ /* Tell js_EmitTree to generate a final POP. */
2467
+ pn->pn_extra |= PNX_POPVAR;
2468
+ break;
2469
+
2470
+ case TOK_RETURN:
2471
+ if (!(tc->flags & TCF_IN_FUNCTION)) {
2472
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2473
+ JSMSG_BAD_RETURN);
2474
+ return NULL;
2475
+ }
2476
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
2477
+ if (!pn)
2478
+ return NULL;
2479
+
2480
+ /* This is ugly, but we don't want to require a semicolon. */
2481
+ ts->flags |= TSF_OPERAND;
2482
+ tt = js_PeekTokenSameLine(cx, ts);
2483
+ ts->flags &= ~TSF_OPERAND;
2484
+ if (tt == TOK_ERROR)
2485
+ return NULL;
2486
+
2487
+ if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
2488
+ pn2 = Expr(cx, ts, tc);
2489
+ if (!pn2)
2490
+ return NULL;
2491
+ tc->flags |= TCF_RETURN_EXPR;
2492
+ pn->pn_pos.end = pn2->pn_pos.end;
2493
+ pn->pn_kid = pn2;
2494
+ } else {
2495
+ tc->flags |= TCF_RETURN_VOID;
2496
+ pn->pn_kid = NULL;
2497
+ }
2498
+
2499
+ if (JS_HAS_STRICT_OPTION(cx) &&
2500
+ (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0) {
2501
+ /*
2502
+ * We must be in a frame with a non-native function, because
2503
+ * we're compiling one.
2504
+ */
2505
+ if (!ReportNoReturnValue(cx, ts))
2506
+ return NULL;
2507
+ }
2508
+ break;
2509
+
2510
+ case TOK_LC:
2511
+ if (cx->lint && (tc->topStmt == NULL || tc->topStmt->type == STMT_BLOCK)) {
2512
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
2513
+ JSREPORT_WARNING |
2514
+ JSREPORT_STRICT,
2515
+ JSMSG_MEANINGLESS_BLOCK)) {
2516
+ return NULL;
2517
+ }
2518
+ }
2519
+ js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
2520
+ pn = Statements(cx, ts, tc);
2521
+ if (!pn)
2522
+ return NULL;
2523
+
2524
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
2525
+ js_PopStatement(tc);
2526
+ return pn;
2527
+
2528
+ case TOK_EOL:
2529
+ case TOK_SEMI:
2530
+ if (cx->lint &&
2531
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2532
+ JSREPORT_WARNING |
2533
+ JSREPORT_STRICT,
2534
+ tt == TOK_SEMI ?
2535
+ JSMSG_EMPTY_STATEMENT :
2536
+ JSMSG_MISSING_SEMICOLON)) {
2537
+ return NULL;
2538
+ }
2539
+
2540
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
2541
+ if (!pn)
2542
+ return NULL;
2543
+ pn->pn_type = TOK_SEMI;
2544
+ pn->pn_kid = NULL;
2545
+ return pn;
2546
+
2547
+ #if JS_HAS_DEBUGGER_KEYWORD
2548
+ case TOK_DEBUGGER:
2549
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
2550
+ if (!pn)
2551
+ return NULL;
2552
+ pn->pn_type = TOK_DEBUGGER;
2553
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
2554
+ break;
2555
+ #endif /* JS_HAS_DEBUGGER_KEYWORD */
2556
+
2557
+ case TOK_ERROR:
2558
+ return NULL;
2559
+
2560
+ default:
2561
+ js_UngetToken(ts);
2562
+
2563
+ if (cx->lint)
2564
+ cx->lint->allowIncDec = JS_TRUE;
2565
+ pn2 = Expr(cx, ts, tc);
2566
+ if (cx->lint)
2567
+ cx->lint->allowIncDec = JS_FALSE;
2568
+
2569
+ if (!pn2)
2570
+ return NULL;
2571
+
2572
+ if (cx->lint) {
2573
+ if (!isIncDec(pn2) && !warnIfHasIncDec(cx, ts, pn2))
2574
+ return NULL;
2575
+ }
2576
+
2577
+ if (js_PeekToken(cx, ts) == TOK_COLON) {
2578
+ if (pn2->pn_type != TOK_NAME) {
2579
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2580
+ JSMSG_BAD_LABEL);
2581
+ return NULL;
2582
+ }
2583
+ label = pn2->pn_atom;
2584
+ for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
2585
+ if (stmt->type == STMT_LABEL && stmt->label == label) {
2586
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2587
+ JSMSG_DUPLICATE_LABEL);
2588
+ return NULL;
2589
+ }
2590
+ }
2591
+ (void) js_GetToken(cx, ts);
2592
+
2593
+ if (cx->lint &&
2594
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2595
+ JSREPORT_WARNING |
2596
+ JSREPORT_STRICT,
2597
+ JSMSG_USE_OF_LABEL)) {
2598
+ return NULL;
2599
+ }
2600
+
2601
+ /* Push a label struct and parse the statement. */
2602
+ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
2603
+ stmtInfo.label = label;
2604
+ pn = Statement(cx, ts, tc);
2605
+ if (!pn)
2606
+ return NULL;
2607
+
2608
+ /* Pop the label, set pn_expr, and return early. */
2609
+ js_PopStatement(tc);
2610
+ pn2->pn_type = TOK_COLON;
2611
+ pn2->pn_pos.end = pn->pn_pos.end;
2612
+ pn2->pn_expr = pn;
2613
+ return pn2;
2614
+ }
2615
+
2616
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
2617
+ if (!pn)
2618
+ return NULL;
2619
+ pn->pn_type = TOK_SEMI;
2620
+ pn->pn_pos = pn2->pn_pos;
2621
+ pn->pn_kid = pn2;
2622
+ break;
2623
+ }
2624
+
2625
+ /* Check termination of this primitive statement. */
2626
+ if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
2627
+ tt = js_PeekTokenSameLine(cx, ts);
2628
+ if (tt == TOK_ERROR)
2629
+ return NULL;
2630
+ if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
2631
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2632
+ JSMSG_SEMI_BEFORE_STMNT);
2633
+ return NULL;
2634
+ }
2635
+ }
2636
+
2637
+ if (!js_MatchToken(cx, ts, TOK_SEMI) && cx->lint) {
2638
+ if (!cx->lint->lambdaAssignRequiresSemicolon &&
2639
+ pn &&
2640
+ pn->pn_type == TOK_SEMI &&
2641
+ pn->pn_kid &&
2642
+ pn->pn_kid->pn_type == TOK_ASSIGN &&
2643
+ pn->pn_kid->pn_right &&
2644
+ pn->pn_kid->pn_right->pn_type == TOK_FUNCTION &&
2645
+ pn->pn_kid->pn_right->pn_op == JSOP_ANONFUNOBJ) {
2646
+ /* disregard missing semicolon */
2647
+ }
2648
+ else if (!js_ReportCompileErrorNumber(cx, ts, NULL,
2649
+ JSREPORT_WARNING |
2650
+ JSREPORT_STRICT,
2651
+ JSMSG_MISSING_SEMICOLON)) {
2652
+ return NULL;
2653
+ }
2654
+ }
2655
+ return pn;
2656
+ }
2657
+
2658
+ static JSParseNode *
2659
+ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
2660
+ {
2661
+ JSParseNode *pn, *pn2;
2662
+ JSObject *obj, *pobj;
2663
+ JSStackFrame *fp;
2664
+ JSFunction *fun;
2665
+ JSClass *clasp;
2666
+ JSPropertyOp getter, setter, currentGetter, currentSetter;
2667
+ JSAtom *atom;
2668
+ JSAtomListElement *ale;
2669
+ JSOp prevop;
2670
+ JSProperty *prop;
2671
+ JSScopeProperty *sprop;
2672
+ JSBool ok;
2673
+
2674
+ /*
2675
+ * The tricky part of this code is to create special parsenode opcodes for
2676
+ * getting and setting variables (which will be stored as special slots in
2677
+ * the frame). The complex special case is an eval() inside a function.
2678
+ * If the evaluated string references variables in the enclosing function,
2679
+ * then we need to generate the special variable opcodes. We determine
2680
+ * this by looking up the variable id in the current variable scope.
2681
+ */
2682
+ JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);
2683
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
2684
+ if (!pn)
2685
+ return NULL;
2686
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
2687
+ pn->pn_extra = 0; /* assume no JSOP_POP needed */
2688
+ PN_INIT_LIST(pn);
2689
+
2690
+ /*
2691
+ * Skip eval and debugger frames when looking for the function whose code
2692
+ * is being compiled. If we are called from FunctionBody, TCF_IN_FUNCTION
2693
+ * will be set in tc->flags, and we can be sure fp->fun is the function to
2694
+ * use. But if a function calls eval, the string argument is treated as a
2695
+ * Program (per ECMA), so TCF_IN_FUNCTION won't be set.
2696
+ *
2697
+ * What's more, when the following code is reached from eval, cx->fp->fun
2698
+ * is eval's JSFunction (a native function), so we need to skip its frame.
2699
+ * We should find the scripted caller's function frame just below it, but
2700
+ * we code a loop out of paranoia.
2701
+ */
2702
+ for (fp = cx->fp; (fp->flags & JSFRAME_SPECIAL) && fp->down; fp = fp->down)
2703
+ continue;
2704
+ obj = fp->varobj;
2705
+ fun = fp->fun;
2706
+ clasp = OBJ_GET_CLASS(cx, obj);
2707
+ if (fun && clasp == &js_FunctionClass) {
2708
+ /* We are compiling code inside a function */
2709
+ getter = js_GetLocalVariable;
2710
+ setter = js_SetLocalVariable;
2711
+ } else if (fun && clasp == &js_CallClass) {
2712
+ /* We are compiling code from an eval inside a function */
2713
+ getter = js_GetCallVariable;
2714
+ setter = js_SetCallVariable;
2715
+ } else {
2716
+ getter = clasp->getProperty;
2717
+ setter = clasp->setProperty;
2718
+ }
2719
+
2720
+ ok = JS_TRUE;
2721
+ do {
2722
+ currentGetter = getter;
2723
+ currentSetter = setter;
2724
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
2725
+ atom = CURRENT_TOKEN(ts).t_atom;
2726
+
2727
+ ATOM_LIST_SEARCH(ale, &tc->decls, atom);
2728
+ if (ale) {
2729
+ prevop = ALE_JSOP(ale);
2730
+ if (JS_HAS_STRICT_OPTION(cx) ||
2731
+ pn->pn_op == JSOP_DEFCONST ||
2732
+ prevop == JSOP_DEFCONST) {
2733
+ const char *name = js_AtomToPrintableString(cx, atom);
2734
+ if (!name ||
2735
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2736
+ (pn->pn_op != JSOP_DEFCONST &&
2737
+ prevop != JSOP_DEFCONST)
2738
+ ? JSREPORT_WARNING |
2739
+ JSREPORT_STRICT
2740
+ : JSREPORT_ERROR,
2741
+ JSMSG_REDECLARED_VAR,
2742
+ (prevop == JSOP_DEFFUN ||
2743
+ prevop == JSOP_CLOSURE)
2744
+ ? js_function_str
2745
+ : (prevop == JSOP_DEFCONST)
2746
+ ? js_const_str
2747
+ : js_var_str,
2748
+ name)) {
2749
+ return NULL;
2750
+ }
2751
+ }
2752
+ if (pn->pn_op == JSOP_DEFVAR && prevop == JSOP_CLOSURE)
2753
+ tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
2754
+ } else {
2755
+ /* save global identifier for lint */
2756
+ if (cx->lint && cx->lint->scriptIdentifiers && !tc->down) {
2757
+ jsval val;
2758
+ val = INT_TO_JSVAL(0);
2759
+ if (!js_SetProperty(cx, cx->lint->scriptIdentifiers, (jsid)atom, &val))
2760
+ return NULL;
2761
+ }
2762
+ ale = js_IndexAtom(cx, atom, &tc->decls);
2763
+ if (!ale)
2764
+ return NULL;
2765
+ }
2766
+ ALE_SET_JSOP(ale, pn->pn_op);
2767
+
2768
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
2769
+ if (!pn2)
2770
+ return NULL;
2771
+ pn2->pn_op = JSOP_NAME;
2772
+ pn2->pn_atom = atom;
2773
+ pn2->pn_expr = NULL;
2774
+ pn2->pn_slot = -1;
2775
+ pn2->pn_attrs = (pn->pn_op == JSOP_DEFCONST)
2776
+ ? JSPROP_ENUMERATE | JSPROP_PERMANENT |
2777
+ JSPROP_READONLY
2778
+ : JSPROP_ENUMERATE | JSPROP_PERMANENT;
2779
+ pn2->pn_attrs |= JSPROP_LINT_DECLARED;
2780
+ PN_APPEND(pn, pn2);
2781
+
2782
+ if (!fun) {
2783
+ prop = NULL; /* don't lookup global variables at compile time */
2784
+ } else {
2785
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
2786
+ return NULL;
2787
+ }
2788
+ if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
2789
+ sprop = (JSScopeProperty *)prop;
2790
+ if (sprop->getter == js_GetArgument) {
2791
+ const char *name = js_AtomToPrintableString(cx, atom);
2792
+ if (!name) {
2793
+ ok = JS_FALSE;
2794
+ } else if (pn->pn_op == JSOP_DEFCONST) {
2795
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2796
+ JSMSG_REDECLARED_PARAM,
2797
+ name);
2798
+ ok = JS_FALSE;
2799
+ } else {
2800
+ currentGetter = js_GetArgument;
2801
+ currentSetter = js_SetArgument;
2802
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
2803
+ JSREPORT_WARNING |
2804
+ JSREPORT_STRICT,
2805
+ JSMSG_VAR_HIDES_ARG,
2806
+ name);
2807
+ }
2808
+ } else {
2809
+ if (fun) {
2810
+ /* Not an argument, must be a redeclared local var. */
2811
+ if (clasp == &js_FunctionClass) {
2812
+ JS_ASSERT(sprop->getter == js_GetLocalVariable);
2813
+ JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
2814
+ sprop->shortid < fun->nvars);
2815
+ } else if (clasp == &js_CallClass) {
2816
+ if (sprop->getter == js_GetCallVariable) {
2817
+ /*
2818
+ * Referencing a variable introduced by a var
2819
+ * statement in the enclosing function. Check
2820
+ * that the slot number we have is in range.
2821
+ */
2822
+ JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
2823
+ sprop->shortid < fun->nvars);
2824
+ } else {
2825
+ /*
2826
+ * A variable introduced through another eval:
2827
+ * don't use the special getters and setters
2828
+ * since we can't allocate a slot in the frame.
2829
+ */
2830
+ currentGetter = sprop->getter;
2831
+ currentSetter = sprop->setter;
2832
+ }
2833
+ }
2834
+
2835
+ /* Override the old getter and setter, to handle eval. */
2836
+ sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
2837
+ 0, sprop->attrs,
2838
+ currentGetter,
2839
+ currentSetter);
2840
+ if (!sprop)
2841
+ ok = JS_FALSE;
2842
+ }
2843
+ }
2844
+ } else {
2845
+ /*
2846
+ * Property not found in current variable scope: we have not seen
2847
+ * this variable before. Define a new local variable by adding a
2848
+ * property to the function's scope, allocating one slot in the
2849
+ * function's frame. Global variables and any locals declared in
2850
+ * with statement bodies are handled at runtime, by script prolog
2851
+ * JSOP_DEFVAR bytecodes generated for slot-less vars.
2852
+ */
2853
+ sprop = NULL;
2854
+ if (prop) {
2855
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
2856
+ prop = NULL;
2857
+ }
2858
+ if (currentGetter == js_GetCallVariable) {
2859
+ /* Can't increase fun->nvars in an active frame! */
2860
+ currentGetter = clasp->getProperty;
2861
+ currentSetter = clasp->setProperty;
2862
+ }
2863
+ if (currentGetter == js_GetLocalVariable &&
2864
+ atom != cx->runtime->atomState.argumentsAtom &&
2865
+ fp->scopeChain == obj &&
2866
+ !js_InWithStatement(tc)) {
2867
+ if (!js_AddNativeProperty(cx, obj, (jsid)atom,
2868
+ currentGetter, currentSetter,
2869
+ SPROP_INVALID_SLOT,
2870
+ pn2->pn_attrs | JSPROP_SHARED,
2871
+ SPROP_HAS_SHORTID, fun->nvars)) {
2872
+ ok = JS_FALSE;
2873
+ }
2874
+ fun->nvars++;
2875
+ }
2876
+ }
2877
+
2878
+ if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
2879
+ if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
2880
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
2881
+ JSMSG_BAD_VAR_INIT);
2882
+ ok = JS_FALSE;
2883
+ } else {
2884
+ pn2->pn_expr = AssignExpr(cx, ts, tc);
2885
+ if (!pn2->pn_expr) {
2886
+ ok = JS_FALSE;
2887
+ } else {
2888
+ pn2->pn_op = (pn->pn_op == JSOP_DEFCONST)
2889
+ ? JSOP_SETCONST
2890
+ : JSOP_SETNAME;
2891
+ if (atom == cx->runtime->atomState.argumentsAtom)
2892
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
2893
+ if (cx->lint && pn2->pn_expr->pn_type == TOK_NAME &&
2894
+ pn2->pn_expr->pn_atom == atom &&
2895
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2896
+ JSREPORT_WARNING |
2897
+ JSREPORT_STRICT,
2898
+ JSMSG_USELESS_ASSIGN)) {
2899
+ return NULL;
2900
+ }
2901
+ }
2902
+ }
2903
+ }
2904
+
2905
+ if (prop)
2906
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
2907
+ if (!ok)
2908
+ return NULL;
2909
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
2910
+
2911
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
2912
+ return pn;
2913
+ }
2914
+
2915
+ static JSParseNode *
2916
+ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
2917
+ {
2918
+ JSParseNode *pn, *pn2;
2919
+
2920
+ pn = AssignExpr(cx, ts, tc);
2921
+ if (pn && js_MatchToken(cx, ts, TOK_COMMA)) {
2922
+ /* allow commas in first and last expressions of for loop */
2923
+ if (cx->lint && (tc->flags & TCF_IN_FOR_INIT) == 0 && (tc->flags & TCF_IN_FOR_POST) == 0 &&
2924
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2925
+ JSREPORT_WARNING |
2926
+ JSREPORT_STRICT,
2927
+ JSMSG_COMMA_SEPARATED_STMTS)) {
2928
+ return NULL;
2929
+ }
2930
+
2931
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
2932
+ if (!pn2)
2933
+ return NULL;
2934
+ pn2->pn_pos.begin = pn->pn_pos.begin;
2935
+ PN_INIT_LIST_1(pn2, pn);
2936
+ pn = pn2;
2937
+ do {
2938
+ pn2 = AssignExpr(cx, ts, tc);
2939
+ if (!pn2)
2940
+ return NULL;
2941
+ PN_APPEND(pn, pn2);
2942
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
2943
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
2944
+ }
2945
+ return pn;
2946
+ }
2947
+
2948
+ static JSParseNode *
2949
+ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
2950
+ {
2951
+ JSParseNode *pn, *pn2;
2952
+ JSTokenType tt;
2953
+ JSOp op;
2954
+
2955
+ CHECK_RECURSION();
2956
+
2957
+ pn = CondExpr(cx, ts, tc);
2958
+ if (!pn)
2959
+ return NULL;
2960
+
2961
+ if (cx->lint && !cx->lint->allowIncDec && !warnIfHasIncDec(cx, ts, pn))
2962
+ return NULL;
2963
+
2964
+ tt = js_GetToken(cx, ts);
2965
+ #if JS_HAS_GETTER_SETTER
2966
+ if (tt == TOK_NAME) {
2967
+ tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN);
2968
+ if (tt == TOK_ERROR)
2969
+ return NULL;
2970
+ }
2971
+ #endif
2972
+ if (tt != TOK_ASSIGN) {
2973
+ js_UngetToken(ts);
2974
+ return pn;
2975
+ }
2976
+
2977
+ op = CURRENT_TOKEN(ts).t_op;
2978
+ for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)
2979
+ continue;
2980
+ switch (pn2->pn_type) {
2981
+ case TOK_NAME:
2982
+ pn2->pn_op = JSOP_SETNAME;
2983
+ if (pn2->pn_atom == cx->runtime->atomState.argumentsAtom)
2984
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
2985
+ break;
2986
+ case TOK_DOT:
2987
+ pn2->pn_op = JSOP_SETPROP;
2988
+ break;
2989
+ case TOK_LB:
2990
+ pn2->pn_op = JSOP_SETELEM;
2991
+ break;
2992
+ #if JS_HAS_LVALUE_RETURN
2993
+ case TOK_LP:
2994
+ pn2->pn_op = JSOP_SETCALL;
2995
+ if (cx->lint &&
2996
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
2997
+ JSREPORT_WARNING | JSREPORT_STRICT,
2998
+ JSMSG_ASSIGN_TO_FUNCTION_CALL)) {
2999
+ return NULL;
3000
+ }
3001
+ break;
3002
+ #endif
3003
+ default:
3004
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3005
+ JSMSG_BAD_LEFTSIDE_OF_ASS);
3006
+ return NULL;
3007
+ }
3008
+ pn = NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc), tc);
3009
+ if (cx->lint && pn &&
3010
+ pn->pn_left && pn->pn_left->pn_type == TOK_NAME &&
3011
+ pn->pn_right && pn->pn_right->pn_type == TOK_NAME &&
3012
+ pn->pn_left->pn_atom == pn->pn_right->pn_atom &&
3013
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
3014
+ JSREPORT_WARNING |
3015
+ JSREPORT_STRICT,
3016
+ JSMSG_USELESS_ASSIGN)) {
3017
+ return NULL;
3018
+ }
3019
+ return pn;
3020
+ }
3021
+
3022
+ static JSParseNode *
3023
+ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3024
+ {
3025
+ JSParseNode *pn, *pn1, *pn2, *pn3;
3026
+ #if JS_HAS_IN_OPERATOR
3027
+ uintN oldflags;
3028
+ #endif /* JS_HAS_IN_OPERATOR */
3029
+
3030
+ pn = OrExpr(cx, ts, tc);
3031
+ if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {
3032
+ pn1 = pn;
3033
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
3034
+ if (!pn)
3035
+ return NULL;
3036
+ #if JS_HAS_IN_OPERATOR
3037
+ /*
3038
+ * Always accept the 'in' operator in the middle clause of a ternary,
3039
+ * where it's unambiguous, even if we might be parsing the init of a
3040
+ * for statement.
3041
+ */
3042
+ oldflags = tc->flags;
3043
+ tc->flags &= ~TCF_IN_FOR_INIT;
3044
+ #endif /* JS_HAS_IN_OPERATOR */
3045
+ pn2 = AssignExpr(cx, ts, tc);
3046
+ #if JS_HAS_IN_OPERATOR
3047
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
3048
+ #endif /* JS_HAS_IN_OPERATOR */
3049
+
3050
+ if (!pn2)
3051
+ return NULL;
3052
+ MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
3053
+ pn3 = AssignExpr(cx, ts, tc);
3054
+ if (!pn3)
3055
+ return NULL;
3056
+ pn->pn_pos.begin = pn1->pn_pos.begin;
3057
+ pn->pn_pos.end = pn3->pn_pos.end;
3058
+ pn->pn_kid1 = pn1;
3059
+ pn->pn_kid2 = pn2;
3060
+ pn->pn_kid3 = pn3;
3061
+ }
3062
+ return pn;
3063
+ }
3064
+
3065
+ static JSParseNode *
3066
+ OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3067
+ {
3068
+ JSParseNode *pn;
3069
+
3070
+ pn = AndExpr(cx, ts, tc);
3071
+ if (pn && js_MatchToken(cx, ts, TOK_OR))
3072
+ pn = NewBinary(cx, TOK_OR, JSOP_OR, pn, OrExpr(cx, ts, tc), tc);
3073
+ return pn;
3074
+ }
3075
+
3076
+ static JSParseNode *
3077
+ AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3078
+ {
3079
+ JSParseNode *pn;
3080
+
3081
+ pn = BitOrExpr(cx, ts, tc);
3082
+ if (pn && js_MatchToken(cx, ts, TOK_AND))
3083
+ pn = NewBinary(cx, TOK_AND, JSOP_AND, pn, AndExpr(cx, ts, tc), tc);
3084
+ return pn;
3085
+ }
3086
+
3087
+ static JSParseNode *
3088
+ BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3089
+ {
3090
+ JSParseNode *pn;
3091
+
3092
+ pn = BitXorExpr(cx, ts, tc);
3093
+ while (pn && js_MatchToken(cx, ts, TOK_BITOR)) {
3094
+ pn = NewBinary(cx, TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc),
3095
+ tc);
3096
+ }
3097
+ return pn;
3098
+ }
3099
+
3100
+ static JSParseNode *
3101
+ BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3102
+ {
3103
+ JSParseNode *pn;
3104
+
3105
+ pn = BitAndExpr(cx, ts, tc);
3106
+ while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) {
3107
+ pn = NewBinary(cx, TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc),
3108
+ tc);
3109
+ }
3110
+ return pn;
3111
+ }
3112
+
3113
+ static JSParseNode *
3114
+ BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3115
+ {
3116
+ JSParseNode *pn;
3117
+
3118
+ pn = EqExpr(cx, ts, tc);
3119
+ while (pn && js_MatchToken(cx, ts, TOK_BITAND))
3120
+ pn = NewBinary(cx, TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc);
3121
+ return pn;
3122
+ }
3123
+
3124
+ static JSBool
3125
+ AllowImplicitConversionOnCompare(JSContext *cx, JSParseNode *pn)
3126
+ {
3127
+ if (pn->pn_type == TOK_PRIMARY &&
3128
+ (pn->pn_op == JSOP_NULL || pn->pn_op == JSOP_TRUE || pn->pn_op == JSOP_FALSE)) {
3129
+ return JS_FALSE;
3130
+ }
3131
+
3132
+ if (pn->pn_type == TOK_STRING && pn->pn_op == JSOP_STRING &&
3133
+ JSSTRING_LENGTH(ATOM_TO_STRING(pn->pn_atom)) == 0) {
3134
+ return JS_FALSE;
3135
+ }
3136
+
3137
+ if (pn->pn_type == TOK_NUMBER && pn->pn_dval == 0) {
3138
+ return JS_FALSE;
3139
+ }
3140
+
3141
+ return JS_TRUE;
3142
+ }
3143
+
3144
+ static JSParseNode *
3145
+ EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3146
+ {
3147
+ JSParseNode *pn;
3148
+ JSOp op;
3149
+
3150
+ pn = RelExpr(cx, ts, tc);
3151
+ while (pn && js_MatchToken(cx, ts, TOK_EQOP)) {
3152
+ op = CURRENT_TOKEN(ts).t_op;
3153
+ pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc);
3154
+
3155
+ if (cx->lint && pn && pn->pn_left && pn->pn_right) {
3156
+ if (pn->pn_op != JSOP_NEW_EQ && pn->pn_op != JSOP_NEW_NE &&
3157
+ (!AllowImplicitConversionOnCompare(cx, pn->pn_left) ||
3158
+ !AllowImplicitConversionOnCompare(cx, pn->pn_right))) {
3159
+
3160
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
3161
+ JSREPORT_WARNING |
3162
+ JSREPORT_STRICT,
3163
+ JSMSG_COMPARISON_TYPE_CONV)) {
3164
+ return NULL;
3165
+ }
3166
+ }
3167
+ if (AreExpressionsIdentical(cx, pn->pn_left, pn->pn_right, JS_FALSE) &&
3168
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
3169
+ JSREPORT_WARNING |
3170
+ JSREPORT_STRICT,
3171
+ JSMSG_USELESS_COMPARISON)) {
3172
+ return NULL;
3173
+ }
3174
+ }
3175
+ }
3176
+ return pn;
3177
+ }
3178
+
3179
+ static JSParseNode *
3180
+ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3181
+ {
3182
+ JSParseNode *pn;
3183
+ JSTokenType tt;
3184
+ JSOp op;
3185
+ #if JS_HAS_IN_OPERATOR
3186
+ uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT;
3187
+
3188
+ /*
3189
+ * Uses of the in operator in ShiftExprs are always unambiguous,
3190
+ * so unset the flag that prohibits recognizing it.
3191
+ */
3192
+ tc->flags &= ~TCF_IN_FOR_INIT;
3193
+ #endif /* JS_HAS_IN_OPERATOR */
3194
+
3195
+ pn = ShiftExpr(cx, ts, tc);
3196
+ while (pn &&
3197
+ (js_MatchToken(cx, ts, TOK_RELOP)
3198
+ #if JS_HAS_IN_OPERATOR
3199
+ /*
3200
+ * Recognize the 'in' token as an operator only if we're not
3201
+ * currently in the init expr of a for loop.
3202
+ */
3203
+ || (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN))
3204
+ #endif /* JS_HAS_IN_OPERATOR */
3205
+ #if JS_HAS_INSTANCEOF
3206
+ || js_MatchToken(cx, ts, TOK_INSTANCEOF)
3207
+ #endif /* JS_HAS_INSTANCEOF */
3208
+ )) {
3209
+ tt = CURRENT_TOKEN(ts).type;
3210
+ op = CURRENT_TOKEN(ts).t_op;
3211
+ pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc), tc);
3212
+
3213
+ if (cx->lint && pn && pn->pn_left && pn->pn_right &&
3214
+ AreExpressionsIdentical(cx, pn->pn_left, pn->pn_right, JS_FALSE) &&
3215
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
3216
+ JSREPORT_WARNING |
3217
+ JSREPORT_STRICT,
3218
+ JSMSG_USELESS_COMPARISON)) {
3219
+ return NULL;
3220
+ }
3221
+ }
3222
+ #if JS_HAS_IN_OPERATOR
3223
+ /* Restore previous state of inForInit flag. */
3224
+ tc->flags |= inForInitFlag;
3225
+ #endif /* JS_HAS_IN_OPERATOR */
3226
+
3227
+ return pn;
3228
+ }
3229
+
3230
+ static JSParseNode *
3231
+ ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3232
+ {
3233
+ JSParseNode *pn;
3234
+ JSOp op;
3235
+
3236
+ pn = AddExpr(cx, ts, tc);
3237
+ while (pn && js_MatchToken(cx, ts, TOK_SHOP)) {
3238
+ op = CURRENT_TOKEN(ts).t_op;
3239
+ pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc);
3240
+ }
3241
+ return pn;
3242
+ }
3243
+
3244
+ static JSParseNode *
3245
+ AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3246
+ {
3247
+ JSParseNode *pn;
3248
+ JSTokenType tt;
3249
+ JSOp op;
3250
+
3251
+ pn = MulExpr(cx, ts, tc);
3252
+ while (pn &&
3253
+ (js_MatchToken(cx, ts, TOK_PLUS) ||
3254
+ js_MatchToken(cx, ts, TOK_MINUS))) {
3255
+ tt = CURRENT_TOKEN(ts).type;
3256
+ op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
3257
+ pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc), tc);
3258
+ }
3259
+ return pn;
3260
+ }
3261
+
3262
+ static JSParseNode *
3263
+ MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3264
+ {
3265
+ JSParseNode *pn;
3266
+ JSTokenType tt;
3267
+ JSOp op;
3268
+
3269
+ pn = UnaryExpr(cx, ts, tc);
3270
+ while (pn &&
3271
+ (js_MatchToken(cx, ts, TOK_STAR) ||
3272
+ js_MatchToken(cx, ts, TOK_DIVOP))) {
3273
+ tt = CURRENT_TOKEN(ts).type;
3274
+ op = CURRENT_TOKEN(ts).t_op;
3275
+ pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc), tc);
3276
+ }
3277
+ return pn;
3278
+ }
3279
+
3280
+ static JSParseNode *
3281
+ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSParseNode *kid,
3282
+ const char *name)
3283
+ {
3284
+ while (kid->pn_type == TOK_RP)
3285
+ kid = kid->pn_kid;
3286
+ if (kid->pn_type != TOK_NAME &&
3287
+ kid->pn_type != TOK_DOT &&
3288
+ #if JS_HAS_LVALUE_RETURN
3289
+ (kid->pn_type != TOK_LP || kid->pn_op != JSOP_CALL) &&
3290
+ #endif
3291
+ kid->pn_type != TOK_LB) {
3292
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3293
+ JSMSG_BAD_OPERAND, name);
3294
+ return NULL;
3295
+ }
3296
+ pn->pn_kid = kid;
3297
+ return kid;
3298
+ }
3299
+
3300
+ static const char *incop_name_str[] = {"increment", "decrement"};
3301
+
3302
+ static JSBool
3303
+ SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
3304
+ JSParseNode *pn, JSParseNode *kid,
3305
+ JSTokenType tt, JSBool preorder)
3306
+ {
3307
+ JSOp op;
3308
+
3309
+ kid = SetLvalKid(cx, ts, pn, kid, incop_name_str[tt == TOK_DEC]);
3310
+ if (!kid)
3311
+ return JS_FALSE;
3312
+ switch (kid->pn_type) {
3313
+ case TOK_NAME:
3314
+ op = (tt == TOK_INC)
3315
+ ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
3316
+ : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
3317
+ if (kid->pn_atom == cx->runtime->atomState.argumentsAtom)
3318
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
3319
+ break;
3320
+
3321
+ case TOK_DOT:
3322
+ op = (tt == TOK_INC)
3323
+ ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)
3324
+ : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);
3325
+ break;
3326
+
3327
+ #if JS_HAS_LVALUE_RETURN
3328
+ case TOK_LP:
3329
+ kid->pn_op = JSOP_SETCALL;
3330
+ #endif
3331
+ case TOK_LB:
3332
+ op = (tt == TOK_INC)
3333
+ ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
3334
+ : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
3335
+ break;
3336
+
3337
+ default:
3338
+ JS_ASSERT(0);
3339
+ op = JSOP_NOP;
3340
+ }
3341
+ pn->pn_op = op;
3342
+ return JS_TRUE;
3343
+ }
3344
+
3345
+ static JSParseNode *
3346
+ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3347
+ {
3348
+ JSTokenType tt;
3349
+ JSParseNode *pn, *pn2;
3350
+
3351
+ ts->flags |= TSF_OPERAND;
3352
+ tt = js_GetToken(cx, ts);
3353
+ ts->flags &= ~TSF_OPERAND;
3354
+
3355
+ switch (tt) {
3356
+ case TOK_UNARYOP:
3357
+ case TOK_PLUS:
3358
+ case TOK_MINUS:
3359
+ if (cx->lint && tt == TOK_UNARYOP && CURRENT_TOKEN(ts).t_op == JSOP_VOID &&
3360
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
3361
+ JSREPORT_WARNING |
3362
+ JSREPORT_STRICT,
3363
+ JSMSG_USELESS_VOID)) {
3364
+ return NULL;
3365
+ }
3366
+
3367
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3368
+ if (!pn)
3369
+ return NULL;
3370
+ pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */
3371
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
3372
+ pn2 = UnaryExpr(cx, ts, tc);
3373
+ if (!pn2)
3374
+ return NULL;
3375
+ pn->pn_pos.end = pn2->pn_pos.end;
3376
+ pn->pn_kid = pn2;
3377
+ break;
3378
+
3379
+ case TOK_INC:
3380
+ case TOK_DEC:
3381
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3382
+ if (!pn)
3383
+ return NULL;
3384
+ pn2 = MemberExpr(cx, ts, tc, JS_TRUE);
3385
+ if (!pn2)
3386
+ return NULL;
3387
+ if (!SetIncOpKid(cx, ts, tc, pn, pn2, tt, JS_TRUE))
3388
+ return NULL;
3389
+ pn->pn_pos.end = pn2->pn_pos.end;
3390
+ break;
3391
+
3392
+ case TOK_DELETE:
3393
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3394
+ if (!pn)
3395
+ return NULL;
3396
+ pn2 = UnaryExpr(cx, ts, tc);
3397
+ if (!pn2)
3398
+ return NULL;
3399
+ pn->pn_pos.end = pn2->pn_pos.end;
3400
+
3401
+ /*
3402
+ * Under ECMA3, deleting any unary expression is valid -- it simply
3403
+ * returns true. Here we strip off any parentheses.
3404
+ */
3405
+ while (pn2->pn_type == TOK_RP)
3406
+ pn2 = pn2->pn_kid;
3407
+ pn->pn_kid = pn2;
3408
+ break;
3409
+
3410
+ case TOK_ERROR:
3411
+ return NULL;
3412
+
3413
+ default:
3414
+ js_UngetToken(ts);
3415
+ pn = MemberExpr(cx, ts, tc, JS_TRUE);
3416
+ if (!pn)
3417
+ return NULL;
3418
+
3419
+ /* Don't look across a newline boundary for a postfix incop. */
3420
+ if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
3421
+ tt = js_PeekTokenSameLine(cx, ts);
3422
+ if (tt == TOK_INC || tt == TOK_DEC) {
3423
+ (void) js_GetToken(cx, ts);
3424
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3425
+ if (!pn2)
3426
+ return NULL;
3427
+ if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE))
3428
+ return NULL;
3429
+ pn2->pn_pos.begin = pn->pn_pos.begin;
3430
+ pn = pn2;
3431
+
3432
+ if (cx->lint && ((tt == TOK_INC && js_PeekToken(cx, ts) == TOK_PLUS) ||
3433
+ (tt == TOK_DEC && js_PeekToken(cx, ts) == TOK_MINUS)) &&
3434
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
3435
+ JSREPORT_WARNING |
3436
+ JSREPORT_STRICT,
3437
+ JSMSG_MULTIPLE_PLUS_MINUS))
3438
+ {
3439
+ return NULL;
3440
+ }
3441
+ }
3442
+ }
3443
+ break;
3444
+ }
3445
+ return pn;
3446
+ }
3447
+
3448
+ static JSBool
3449
+ ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
3450
+ JSParseNode *listNode)
3451
+ {
3452
+ JSBool matched;
3453
+
3454
+ ts->flags |= TSF_OPERAND;
3455
+ matched = js_MatchToken(cx, ts, TOK_RP);
3456
+ ts->flags &= ~TSF_OPERAND;
3457
+ if (!matched) {
3458
+ do {
3459
+ JSParseNode *argNode = AssignExpr(cx, ts, tc);
3460
+ if (!argNode)
3461
+ return JS_FALSE;
3462
+ PN_APPEND(listNode, argNode);
3463
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
3464
+
3465
+ if (js_GetToken(cx, ts) != TOK_RP) {
3466
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3467
+ JSMSG_PAREN_AFTER_ARGS);
3468
+ return JS_FALSE;
3469
+ }
3470
+ }
3471
+ return JS_TRUE;
3472
+ }
3473
+
3474
+ static JSParseNode *
3475
+ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
3476
+ JSBool allowCallSyntax)
3477
+ {
3478
+ JSParseNode *pn, *pn2, *pn3;
3479
+ JSTokenType tt;
3480
+
3481
+ CHECK_RECURSION();
3482
+
3483
+ /* Check for new expression first. */
3484
+ ts->flags |= TSF_OPERAND;
3485
+ tt = js_PeekToken(cx, ts);
3486
+ ts->flags &= ~TSF_OPERAND;
3487
+ if (tt == TOK_NEW) {
3488
+ (void) js_GetToken(cx, ts);
3489
+
3490
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
3491
+ if (!pn)
3492
+ return NULL;
3493
+ pn2 = MemberExpr(cx, ts, tc, JS_FALSE);
3494
+ if (!pn2)
3495
+ return NULL;
3496
+ pn->pn_op = JSOP_NEW;
3497
+ PN_INIT_LIST_1(pn, pn2);
3498
+ pn->pn_pos.begin = pn2->pn_pos.begin;
3499
+
3500
+ if (js_MatchToken(cx, ts, TOK_LP) && !ArgumentList(cx, ts, tc, pn))
3501
+ return NULL;
3502
+ if (pn->pn_count > ARGC_LIMIT) {
3503
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3504
+ JSMSG_TOO_MANY_CON_ARGS);
3505
+ return NULL;
3506
+ }
3507
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
3508
+ } else {
3509
+ pn = PrimaryExpr(cx, ts, tc);
3510
+ if (!pn)
3511
+ return NULL;
3512
+ }
3513
+
3514
+ while ((tt = js_GetToken(cx, ts)) > TOK_EOF) {
3515
+ if (tt == TOK_DOT) {
3516
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
3517
+ if (!pn2)
3518
+ return NULL;
3519
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
3520
+ pn2->pn_pos.begin = pn->pn_pos.begin;
3521
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3522
+ pn2->pn_op = JSOP_GETPROP;
3523
+ pn2->pn_expr = pn;
3524
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
3525
+ } else if (tt == TOK_LB) {
3526
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
3527
+ if (!pn2)
3528
+ return NULL;
3529
+ pn3 = Expr(cx, ts, tc);
3530
+ if (!pn3)
3531
+ return NULL;
3532
+
3533
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
3534
+ pn2->pn_pos.begin = pn->pn_pos.begin;
3535
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3536
+
3537
+ /* Optimize o['p'] to o.p by rewriting pn2. */
3538
+ if (pn3->pn_type == TOK_STRING) {
3539
+ pn2->pn_type = TOK_DOT;
3540
+ pn2->pn_op = JSOP_GETPROP;
3541
+ pn2->pn_arity = PN_NAME;
3542
+ pn2->pn_expr = pn;
3543
+ pn2->pn_atom = pn3->pn_atom;
3544
+ } else {
3545
+ pn2->pn_op = JSOP_GETELEM;
3546
+ pn2->pn_left = pn;
3547
+ pn2->pn_right = pn3;
3548
+ }
3549
+ } else if (allowCallSyntax && tt == TOK_LP) {
3550
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
3551
+ if (!pn2)
3552
+ return NULL;
3553
+
3554
+ /* Pick JSOP_EVAL and flag tc as heavyweight if eval(...). */
3555
+ pn2->pn_op = JSOP_CALL;
3556
+ if (pn->pn_op == JSOP_NAME &&
3557
+ pn->pn_atom == cx->runtime->atomState.evalAtom) {
3558
+ pn2->pn_op = JSOP_EVAL;
3559
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
3560
+ }
3561
+
3562
+ PN_INIT_LIST_1(pn2, pn);
3563
+ pn2->pn_pos.begin = pn->pn_pos.begin;
3564
+
3565
+ if (!ArgumentList(cx, ts, tc, pn2))
3566
+ return NULL;
3567
+ if (pn2->pn_count > ARGC_LIMIT) {
3568
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3569
+ JSMSG_TOO_MANY_FUN_ARGS);
3570
+ return NULL;
3571
+ }
3572
+ if (pn->pn_op == JSOP_NAME &&
3573
+ pn->pn_atom == cx->runtime->atomState.lazy.parseIntAtom && pn2->pn_count <= 2 &&
3574
+ !js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT,
3575
+ JSMSG_PARSEINT_MISSING_RADIX,
3576
+ js_AtomToPrintableString(cx, pn->pn_atom))) {
3577
+ return NULL;
3578
+ }
3579
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3580
+ } else {
3581
+ js_UngetToken(ts);
3582
+ return pn;
3583
+ }
3584
+
3585
+ pn = pn2;
3586
+ }
3587
+ if (tt == TOK_ERROR)
3588
+ return NULL;
3589
+ return pn;
3590
+ }
3591
+
3592
+ static JSParseNode *
3593
+ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
3594
+ {
3595
+ JSTokenType tt;
3596
+ JSParseNode *pn, *pn2, *pn3;
3597
+ char *badWord;
3598
+ #if JS_HAS_GETTER_SETTER
3599
+ JSAtom *atom;
3600
+ JSRuntime *rt;
3601
+ #endif
3602
+
3603
+ #if JS_HAS_SHARP_VARS
3604
+ JSParseNode *defsharp;
3605
+ JSBool notsharp;
3606
+
3607
+ defsharp = NULL;
3608
+ notsharp = JS_FALSE;
3609
+ again:
3610
+ /*
3611
+ * Control flows here after #n= is scanned. If the following primary is
3612
+ * not valid after such a "sharp variable" definition, the tt switch case
3613
+ * should set notsharp.
3614
+ */
3615
+ #endif
3616
+
3617
+ CHECK_RECURSION();
3618
+
3619
+ ts->flags |= TSF_OPERAND;
3620
+ tt = js_GetToken(cx, ts);
3621
+ ts->flags &= ~TSF_OPERAND;
3622
+
3623
+ #if JS_HAS_GETTER_SETTER
3624
+ if (tt == TOK_NAME) {
3625
+ tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
3626
+ if (tt == TOK_ERROR)
3627
+ return NULL;
3628
+ }
3629
+ #endif
3630
+
3631
+ switch (tt) {
3632
+ #if JS_HAS_LEXICAL_CLOSURE
3633
+ case TOK_FUNCTION:
3634
+ pn = FunctionExpr(cx, ts, tc);
3635
+ if (!pn)
3636
+ return NULL;
3637
+ break;
3638
+ #endif
3639
+
3640
+ #if JS_HAS_INITIALIZERS
3641
+ case TOK_LB:
3642
+ {
3643
+ JSBool matched;
3644
+ jsuint atomIndex;
3645
+
3646
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
3647
+ if (!pn)
3648
+ return NULL;
3649
+ pn->pn_type = TOK_RB;
3650
+ pn->pn_extra = 0;
3651
+
3652
+ #if JS_HAS_SHARP_VARS
3653
+ if (defsharp) {
3654
+ PN_INIT_LIST_1(pn, defsharp);
3655
+ defsharp = NULL;
3656
+ } else
3657
+ #endif
3658
+ PN_INIT_LIST(pn);
3659
+
3660
+ ts->flags |= TSF_OPERAND;
3661
+ matched = js_MatchToken(cx, ts, TOK_RB);
3662
+ ts->flags &= ~TSF_OPERAND;
3663
+ if (!matched) {
3664
+ for (atomIndex = 0; atomIndex < ATOM_INDEX_LIMIT; atomIndex++) {
3665
+ ts->flags |= TSF_OPERAND;
3666
+ tt = js_PeekToken(cx, ts);
3667
+ ts->flags &= ~TSF_OPERAND;
3668
+ if (tt == TOK_RB) {
3669
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
3670
+ JSREPORT_WARNING |
3671
+ JSREPORT_STRICT,
3672
+ JSMSG_TRAILING_COMMA_IN_ARRAY)) {
3673
+ return NULL;
3674
+ }
3675
+ pn->pn_extra |= PNX_ENDCOMMA;
3676
+ break;
3677
+ }
3678
+
3679
+ if (tt == TOK_COMMA) {
3680
+ /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */
3681
+ js_MatchToken(cx, ts, TOK_COMMA);
3682
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3683
+ } else {
3684
+ pn2 = AssignExpr(cx, ts, tc);
3685
+ }
3686
+ if (!pn2)
3687
+ return NULL;
3688
+ PN_APPEND(pn, pn2);
3689
+
3690
+ if (tt != TOK_COMMA) {
3691
+ /* If we didn't already match TOK_COMMA in above case. */
3692
+ if (!js_MatchToken(cx, ts, TOK_COMMA))
3693
+ break;
3694
+ }
3695
+ }
3696
+
3697
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
3698
+ }
3699
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3700
+ return pn;
3701
+ }
3702
+
3703
+ case TOK_LC:
3704
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
3705
+ if (!pn)
3706
+ return NULL;
3707
+ pn->pn_type = TOK_RC;
3708
+
3709
+ #if JS_HAS_SHARP_VARS
3710
+ if (defsharp) {
3711
+ PN_INIT_LIST_1(pn, defsharp);
3712
+ defsharp = NULL;
3713
+ } else
3714
+ #endif
3715
+ PN_INIT_LIST(pn);
3716
+
3717
+ if (!js_MatchToken(cx, ts, TOK_RC)) {
3718
+ do {
3719
+ JSOp op;
3720
+
3721
+ tt = js_GetToken(cx, ts);
3722
+ switch (tt) {
3723
+ case TOK_NUMBER:
3724
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3725
+ if (pn3)
3726
+ pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
3727
+ break;
3728
+ case TOK_NAME:
3729
+ #if JS_HAS_GETTER_SETTER
3730
+ atom = CURRENT_TOKEN(ts).t_atom;
3731
+ rt = cx->runtime;
3732
+ if (atom == rt->atomState.getAtom ||
3733
+ atom == rt->atomState.setAtom) {
3734
+ op = (atom == rt->atomState.getAtom)
3735
+ ? JSOP_GETTER
3736
+ : JSOP_SETTER;
3737
+ if (js_MatchToken(cx, ts, TOK_NAME)) {
3738
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME,
3739
+ tc);
3740
+ if (!pn3)
3741
+ return NULL;
3742
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
3743
+ pn3->pn_expr = NULL;
3744
+
3745
+ /* We have to fake a 'function' token here. */
3746
+ CURRENT_TOKEN(ts).t_op = JSOP_NOP;
3747
+ CURRENT_TOKEN(ts).type = TOK_FUNCTION;
3748
+ pn2 = FunctionExpr(cx, ts, tc);
3749
+ pn2 = NewBinary(cx, TOK_COLON, op, pn3, pn2, tc);
3750
+ goto skip;
3751
+ }
3752
+ }
3753
+ /* else fall thru ... */
3754
+ #endif
3755
+ case TOK_STRING:
3756
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3757
+ if (pn3)
3758
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
3759
+ break;
3760
+ case TOK_RC:
3761
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
3762
+ JSREPORT_WARNING |
3763
+ JSREPORT_STRICT,
3764
+ JSMSG_TRAILING_COMMA)) {
3765
+ return NULL;
3766
+ }
3767
+ goto end_obj_init;
3768
+ default:
3769
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3770
+ JSMSG_BAD_PROP_ID);
3771
+ return NULL;
3772
+ }
3773
+
3774
+ tt = js_GetToken(cx, ts);
3775
+ #if JS_HAS_GETTER_SETTER
3776
+ if (tt == TOK_NAME) {
3777
+ tt = CheckGetterOrSetter(cx, ts, TOK_COLON);
3778
+ if (tt == TOK_ERROR)
3779
+ return NULL;
3780
+ }
3781
+ #endif
3782
+ if (tt != TOK_COLON) {
3783
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3784
+ JSMSG_COLON_AFTER_ID);
3785
+ return NULL;
3786
+ }
3787
+ op = CURRENT_TOKEN(ts).t_op;
3788
+ pn2 = NewBinary(cx, TOK_COLON, op, pn3, AssignExpr(cx, ts, tc),
3789
+ tc);
3790
+ pn3->pn_attrs |= JSPROP_LINT_DECLARED;
3791
+ #if JS_HAS_GETTER_SETTER
3792
+ skip:
3793
+ #endif
3794
+ if (!pn2)
3795
+ return NULL;
3796
+ PN_APPEND(pn, pn2);
3797
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
3798
+
3799
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LIST);
3800
+ }
3801
+ end_obj_init:
3802
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3803
+ return pn;
3804
+
3805
+ #if JS_HAS_SHARP_VARS
3806
+ case TOK_DEFSHARP:
3807
+ if (defsharp)
3808
+ goto badsharp;
3809
+ defsharp = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3810
+ if (!defsharp)
3811
+ return NULL;
3812
+ defsharp->pn_kid = NULL;
3813
+ defsharp->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
3814
+ goto again;
3815
+
3816
+ case TOK_USESHARP:
3817
+ /* Check for forward/dangling references at runtime, to allow eval. */
3818
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3819
+ if (!pn)
3820
+ return NULL;
3821
+ pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
3822
+ notsharp = JS_TRUE;
3823
+ break;
3824
+ #endif /* JS_HAS_SHARP_VARS */
3825
+ #endif /* JS_HAS_INITIALIZERS */
3826
+
3827
+ case TOK_LP:
3828
+ {
3829
+ #if JS_HAS_IN_OPERATOR
3830
+ uintN oldflags;
3831
+ #endif
3832
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
3833
+ if (!pn)
3834
+ return NULL;
3835
+ #if JS_HAS_IN_OPERATOR
3836
+ /*
3837
+ * Always accept the 'in' operator in a parenthesized expression,
3838
+ * where it's unambiguous, even if we might be parsing the init of a
3839
+ * for statement.
3840
+ */
3841
+ oldflags = tc->flags;
3842
+ tc->flags &= ~TCF_IN_FOR_INIT;
3843
+ #endif
3844
+ pn2 = Expr(cx, ts, tc);
3845
+ #if JS_HAS_IN_OPERATOR
3846
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
3847
+ #endif
3848
+ if (!pn2)
3849
+ return NULL;
3850
+
3851
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
3852
+ pn->pn_type = TOK_RP;
3853
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
3854
+ pn->pn_kid = pn2;
3855
+ break;
3856
+ }
3857
+
3858
+ case TOK_STRING:
3859
+ #if JS_HAS_SHARP_VARS
3860
+ notsharp = JS_TRUE;
3861
+ #endif
3862
+ /* FALL THROUGH */
3863
+ case TOK_NAME:
3864
+ case TOK_OBJECT:
3865
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3866
+ if (!pn)
3867
+ return NULL;
3868
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
3869
+ pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
3870
+ if (tt == TOK_NAME) {
3871
+ pn->pn_arity = PN_NAME;
3872
+ pn->pn_expr = NULL;
3873
+ pn->pn_slot = -1;
3874
+ pn->pn_attrs = 0;
3875
+
3876
+ /* Unqualified __parent__ and __proto__ uses require activations. */
3877
+ if (pn->pn_atom == cx->runtime->atomState.parentAtom ||
3878
+ pn->pn_atom == cx->runtime->atomState.protoAtom) {
3879
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
3880
+ } else {
3881
+ JSAtomListElement *ale;
3882
+ JSStackFrame *fp;
3883
+ JSStmtInfo *stmt;
3884
+
3885
+ /* Measure optimizable global variable uses. */
3886
+ ATOM_LIST_SEARCH(ale, &tc->decls, pn->pn_atom);
3887
+ if (ale &&
3888
+ !(fp = cx->fp)->fun &&
3889
+ fp->scopeChain == fp->varobj &&
3890
+ !js_InWithStatement(tc) &&
3891
+ !js_InCatchBlock(tc, pn->pn_atom)) {
3892
+ tc->globalUses++;
3893
+ for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
3894
+ if (STMT_IS_LOOP(stmt)) {
3895
+ tc->loopyGlobalUses++;
3896
+ break;
3897
+ }
3898
+ }
3899
+ }
3900
+ }
3901
+
3902
+ if (cx->lint && !MarkIfDeclared(cx, ts, tc, pn))
3903
+ return NULL;
3904
+ }
3905
+ break;
3906
+
3907
+ case TOK_NUMBER:
3908
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3909
+ if (!pn)
3910
+ return NULL;
3911
+ pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
3912
+ #if JS_HAS_SHARP_VARS
3913
+ notsharp = JS_TRUE;
3914
+ #endif
3915
+ break;
3916
+
3917
+ case TOK_PRIMARY:
3918
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
3919
+ if (!pn)
3920
+ return NULL;
3921
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
3922
+ #if JS_HAS_SHARP_VARS
3923
+ notsharp = JS_TRUE;
3924
+ #endif
3925
+ break;
3926
+
3927
+ #if !JS_HAS_EXPORT_IMPORT
3928
+ case TOK_EXPORT:
3929
+ case TOK_IMPORT:
3930
+ #endif
3931
+ case TOK_RESERVED:
3932
+ badWord = js_DeflateString(cx, CURRENT_TOKEN(ts).ptr,
3933
+ (size_t) CURRENT_TOKEN(ts).pos.end.index
3934
+ - CURRENT_TOKEN(ts).pos.begin.index);
3935
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3936
+ JSMSG_RESERVED_ID, badWord);
3937
+ JS_free(cx, badWord);
3938
+ return NULL;
3939
+
3940
+ case TOK_ERROR:
3941
+ /* The scanner or one of its subroutines reported the error. */
3942
+ return NULL;
3943
+
3944
+ default:
3945
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3946
+ JSMSG_SYNTAX_ERROR);
3947
+ return NULL;
3948
+ }
3949
+
3950
+ #if JS_HAS_SHARP_VARS
3951
+ if (defsharp) {
3952
+ if (notsharp) {
3953
+ badsharp:
3954
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
3955
+ JSMSG_BAD_SHARP_VAR_DEF);
3956
+ return NULL;
3957
+ }
3958
+ defsharp->pn_kid = pn;
3959
+ return defsharp;
3960
+ }
3961
+ #endif
3962
+ return pn;
3963
+ }
3964
+
3965
+ static JSBool
3966
+ ContainsVarStmt(JSParseNode *pn)
3967
+ {
3968
+ JSParseNode *pn2;
3969
+
3970
+ if (!pn)
3971
+ return JS_FALSE;
3972
+ switch (pn->pn_arity) {
3973
+ case PN_LIST:
3974
+ if (pn->pn_type == TOK_VAR)
3975
+ return JS_TRUE;
3976
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
3977
+ if (ContainsVarStmt(pn2))
3978
+ return JS_TRUE;
3979
+ }
3980
+ break;
3981
+ case PN_TERNARY:
3982
+ return ContainsVarStmt(pn->pn_kid1) ||
3983
+ ContainsVarStmt(pn->pn_kid2) ||
3984
+ ContainsVarStmt(pn->pn_kid3);
3985
+ case PN_BINARY:
3986
+ /*
3987
+ * Limit recursion if pn is a binary expression, which can't contain a
3988
+ * var statement.
3989
+ */
3990
+ if (pn->pn_op != JSOP_NOP)
3991
+ return JS_FALSE;
3992
+ return ContainsVarStmt(pn->pn_left) || ContainsVarStmt(pn->pn_right);
3993
+ case PN_UNARY:
3994
+ if (pn->pn_op != JSOP_NOP)
3995
+ return JS_FALSE;
3996
+ return ContainsVarStmt(pn->pn_kid);
3997
+ default:;
3998
+ }
3999
+ return JS_FALSE;
4000
+ }
4001
+
4002
+ /*
4003
+ * Fold from one constant type to another.
4004
+ * XXX handles only strings and numbers for now
4005
+ */
4006
+ static JSBool
4007
+ FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type)
4008
+ {
4009
+ if (pn->pn_type != type) {
4010
+ switch (type) {
4011
+ case TOK_NUMBER:
4012
+ if (pn->pn_type == TOK_STRING) {
4013
+ jsdouble d;
4014
+ if (!js_ValueToNumber(cx, ATOM_KEY(pn->pn_atom), &d))
4015
+ return JS_FALSE;
4016
+ pn->pn_dval = d;
4017
+ pn->pn_type = TOK_NUMBER;
4018
+ pn->pn_op = JSOP_NUMBER;
4019
+ }
4020
+ break;
4021
+
4022
+ case TOK_STRING:
4023
+ if (pn->pn_type == TOK_NUMBER) {
4024
+ JSString *str = js_NumberToString(cx, pn->pn_dval);
4025
+ if (!str)
4026
+ return JS_FALSE;
4027
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
4028
+ if (!pn->pn_atom)
4029
+ return JS_FALSE;
4030
+ pn->pn_type = TOK_STRING;
4031
+ pn->pn_op = JSOP_STRING;
4032
+ }
4033
+ break;
4034
+
4035
+ default:;
4036
+ }
4037
+ }
4038
+ return JS_TRUE;
4039
+ }
4040
+
4041
+ /*
4042
+ * Fold two numeric constants. Beware that pn1 and pn2 are recycled, unless
4043
+ * one of them aliases pn, so you can't safely fetch pn2->pn_next, e.g., after
4044
+ * a successful call to this function.
4045
+ */
4046
+ static JSBool
4047
+ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
4048
+ JSParseNode *pn, JSTreeContext *tc)
4049
+ {
4050
+ jsdouble d, d2;
4051
+ int32 i, j;
4052
+ uint32 u;
4053
+
4054
+ JS_ASSERT(pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER);
4055
+ d = pn1->pn_dval;
4056
+ d2 = pn2->pn_dval;
4057
+ switch (op) {
4058
+ case JSOP_LSH:
4059
+ case JSOP_RSH:
4060
+ if (!js_DoubleToECMAInt32(cx, d, &i))
4061
+ return JS_FALSE;
4062
+ if (!js_DoubleToECMAInt32(cx, d2, &j))
4063
+ return JS_FALSE;
4064
+ j &= 31;
4065
+ d = (op == JSOP_LSH) ? i << j : i >> j;
4066
+ break;
4067
+
4068
+ case JSOP_URSH:
4069
+ if (!js_DoubleToECMAUint32(cx, d, &u))
4070
+ return JS_FALSE;
4071
+ if (!js_DoubleToECMAInt32(cx, d2, &j))
4072
+ return JS_FALSE;
4073
+ j &= 31;
4074
+ d = u >> j;
4075
+ break;
4076
+
4077
+ case JSOP_ADD:
4078
+ d += d2;
4079
+ break;
4080
+
4081
+ case JSOP_SUB:
4082
+ d -= d2;
4083
+ break;
4084
+
4085
+ case JSOP_MUL:
4086
+ d *= d2;
4087
+ break;
4088
+
4089
+ case JSOP_DIV:
4090
+ if (d2 == 0) {
4091
+ #if defined(XP_WIN)
4092
+ /* XXX MSVC miscompiles such that (NaN == 0) */
4093
+ if (JSDOUBLE_IS_NaN(d2))
4094
+ d = *cx->runtime->jsNaN;
4095
+ else
4096
+ #endif
4097
+ if (d == 0 || JSDOUBLE_IS_NaN(d))
4098
+ d = *cx->runtime->jsNaN;
4099
+ else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
4100
+ d = *cx->runtime->jsNegativeInfinity;
4101
+ else
4102
+ d = *cx->runtime->jsPositiveInfinity;
4103
+ } else {
4104
+ d /= d2;
4105
+ }
4106
+ break;
4107
+
4108
+ case JSOP_MOD:
4109
+ if (d2 == 0) {
4110
+ d = *cx->runtime->jsNaN;
4111
+ } else {
4112
+ #if defined(XP_WIN)
4113
+ /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
4114
+ if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
4115
+ #endif
4116
+ d = fmod(d, d2);
4117
+ }
4118
+ break;
4119
+
4120
+ default:;
4121
+ }
4122
+
4123
+ /* Take care to allow pn1 or pn2 to alias pn. */
4124
+ if (pn1 != pn)
4125
+ RecycleTree(pn1, tc);
4126
+ if (pn2 != pn)
4127
+ RecycleTree(pn2, tc);
4128
+ pn->pn_type = TOK_NUMBER;
4129
+ pn->pn_op = JSOP_NUMBER;
4130
+ pn->pn_arity = PN_NULLARY;
4131
+ pn->pn_dval = d;
4132
+ return JS_TRUE;
4133
+ }
4134
+
4135
+ JSBool
4136
+ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
4137
+ {
4138
+ JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
4139
+ int stackDummy;
4140
+
4141
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
4142
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
4143
+ return JS_FALSE;
4144
+ }
4145
+
4146
+ switch (pn->pn_arity) {
4147
+ case PN_FUNC:
4148
+ if (!js_FoldConstants(cx, pn->pn_body, tc))
4149
+ return JS_FALSE;
4150
+ break;
4151
+
4152
+ case PN_LIST:
4153
+ /* Save the list head in pn1 for later use. */
4154
+ for (pn1 = pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
4155
+ if (!js_FoldConstants(cx, pn2, tc))
4156
+ return JS_FALSE;
4157
+ }
4158
+ break;
4159
+
4160
+ case PN_TERNARY:
4161
+ /* Any kid may be null (e.g. for (;;)). */
4162
+ pn1 = pn->pn_kid1;
4163
+ pn2 = pn->pn_kid2;
4164
+ pn3 = pn->pn_kid3;
4165
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
4166
+ return JS_FALSE;
4167
+ if (pn2 && !js_FoldConstants(cx, pn2, tc))
4168
+ return JS_FALSE;
4169
+ if (pn3 && !js_FoldConstants(cx, pn3, tc))
4170
+ return JS_FALSE;
4171
+ break;
4172
+
4173
+ case PN_BINARY:
4174
+ /* First kid may be null (for default case in switch). */
4175
+ pn1 = pn->pn_left;
4176
+ pn2 = pn->pn_right;
4177
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
4178
+ return JS_FALSE;
4179
+ if (!js_FoldConstants(cx, pn2, tc))
4180
+ return JS_FALSE;
4181
+ break;
4182
+
4183
+ case PN_UNARY:
4184
+ /* Our kid may be null (e.g. return; vs. return e;). */
4185
+ pn1 = pn->pn_kid;
4186
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
4187
+ return JS_FALSE;
4188
+ break;
4189
+
4190
+ case PN_NAME:
4191
+ /*
4192
+ * Skip pn1 down along a chain of dotted member expressions to avoid
4193
+ * excessive recursion. Our only goal here is to fold constants (if
4194
+ * any) in the primary expression operand to the left of the first
4195
+ * dot in the chain.
4196
+ */
4197
+ pn1 = pn->pn_expr;
4198
+ while (pn1 && pn1->pn_arity == PN_NAME)
4199
+ pn1 = pn1->pn_expr;
4200
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
4201
+ return JS_FALSE;
4202
+ break;
4203
+
4204
+ case PN_NULLARY:
4205
+ break;
4206
+ }
4207
+
4208
+ switch (pn->pn_type) {
4209
+ case TOK_IF:
4210
+ if (ContainsVarStmt(pn2) || ContainsVarStmt(pn3))
4211
+ break;
4212
+ /* FALL THROUGH */
4213
+
4214
+ case TOK_HOOK:
4215
+ /* Reduce 'if (C) T; else E' into T for true C, E for false. */
4216
+ switch (pn1->pn_type) {
4217
+ case TOK_NUMBER:
4218
+ if (pn1->pn_dval == 0)
4219
+ pn2 = pn3;
4220
+ break;
4221
+ case TOK_STRING:
4222
+ if (JSSTRING_LENGTH(ATOM_TO_STRING(pn1->pn_atom)) == 0)
4223
+ pn2 = pn3;
4224
+ break;
4225
+ case TOK_PRIMARY:
4226
+ if (pn1->pn_op == JSOP_TRUE)
4227
+ break;
4228
+ if (pn1->pn_op == JSOP_FALSE || pn1->pn_op == JSOP_NULL) {
4229
+ pn2 = pn3;
4230
+ break;
4231
+ }
4232
+ /* FALL THROUGH */
4233
+ default:
4234
+ /* Early return to dodge common code that copies pn2 to pn. */
4235
+ return JS_TRUE;
4236
+ }
4237
+
4238
+ if (pn2) {
4239
+ /* pn2 is the then- or else-statement subtree to compile. */
4240
+ PN_MOVE_NODE(pn, pn2);
4241
+ } else {
4242
+ /* False condition and no else: make pn an empty statement. */
4243
+ pn->pn_type = TOK_SEMI;
4244
+ pn->pn_arity = PN_UNARY;
4245
+ pn->pn_kid = NULL;
4246
+ }
4247
+ RecycleTree(pn2, tc);
4248
+ if (pn3 && pn3 != pn2)
4249
+ RecycleTree(pn3, tc);
4250
+ break;
4251
+
4252
+ case TOK_PLUS:
4253
+ if (pn->pn_arity == PN_LIST) {
4254
+ size_t length, length2;
4255
+ jschar *chars;
4256
+ JSString *str, *str2;
4257
+
4258
+ /*
4259
+ * Any string literal term with all others number or string means
4260
+ * this is a concatenation. If any term is not a string or number
4261
+ * literal, we can't fold.
4262
+ */
4263
+ JS_ASSERT(pn->pn_count > 2);
4264
+ if (pn->pn_extra & PNX_CANTFOLD)
4265
+ return JS_TRUE;
4266
+ if (pn->pn_extra != PNX_STRCAT)
4267
+ goto do_binary_op;
4268
+
4269
+ /* Ok, we're concatenating: convert non-string constant operands. */
4270
+ length = 0;
4271
+ for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
4272
+ if (!FoldType(cx, pn2, TOK_STRING))
4273
+ return JS_FALSE;
4274
+ /* XXX fold only if all operands convert to string */
4275
+ if (pn2->pn_type != TOK_STRING)
4276
+ return JS_TRUE;
4277
+ length += ATOM_TO_STRING(pn2->pn_atom)->length;
4278
+ }
4279
+
4280
+ /* Allocate a new buffer and string descriptor for the result. */
4281
+ chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
4282
+ if (!chars)
4283
+ return JS_FALSE;
4284
+ str = js_NewString(cx, chars, length, 0);
4285
+ if (!str) {
4286
+ JS_free(cx, chars);
4287
+ return JS_FALSE;
4288
+ }
4289
+
4290
+ /* Fill the buffer, advancing chars and recycling kids as we go. */
4291
+ for (pn2 = pn1; pn2; pn2 = pn3) {
4292
+ str2 = ATOM_TO_STRING(pn2->pn_atom);
4293
+ length2 = str2->length;
4294
+ js_strncpy(chars, str2->chars, length2);
4295
+ chars += length2;
4296
+ pn3 = pn2->pn_next;
4297
+ RecycleTree(pn2, tc);
4298
+ }
4299
+ *chars = 0;
4300
+
4301
+ /* Atomize the result string and mutate pn to refer to it. */
4302
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
4303
+ if (!pn->pn_atom)
4304
+ return JS_FALSE;
4305
+ pn->pn_type = TOK_STRING;
4306
+ pn->pn_op = JSOP_STRING;
4307
+ pn->pn_arity = PN_NULLARY;
4308
+ break;
4309
+ }
4310
+
4311
+ /* Handle a binary string concatenation. */
4312
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
4313
+ if (pn1->pn_type == TOK_STRING || pn2->pn_type == TOK_STRING) {
4314
+ JSString *left, *right, *str;
4315
+
4316
+ if (!FoldType(cx, (pn1->pn_type != TOK_STRING) ? pn1 : pn2,
4317
+ TOK_STRING)) {
4318
+ return JS_FALSE;
4319
+ }
4320
+ if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING)
4321
+ return JS_TRUE;
4322
+ left = ATOM_TO_STRING(pn1->pn_atom);
4323
+ right = ATOM_TO_STRING(pn2->pn_atom);
4324
+ str = js_ConcatStrings(cx, left, right);
4325
+ if (!str)
4326
+ return JS_FALSE;
4327
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
4328
+ if (!pn->pn_atom)
4329
+ return JS_FALSE;
4330
+ pn->pn_type = TOK_STRING;
4331
+ pn->pn_op = JSOP_STRING;
4332
+ pn->pn_arity = PN_NULLARY;
4333
+ RecycleTree(pn1, tc);
4334
+ RecycleTree(pn2, tc);
4335
+ break;
4336
+ }
4337
+
4338
+ /* Can't concatenate string literals, let's try numbers. */
4339
+ goto do_binary_op;
4340
+
4341
+ case TOK_STAR:
4342
+ /* The * in 'import *;' parses as a nullary star node. */
4343
+ if (pn->pn_arity == PN_NULLARY)
4344
+ break;
4345
+ /* FALL THROUGH */
4346
+
4347
+ case TOK_SHOP:
4348
+ case TOK_MINUS:
4349
+ case TOK_DIVOP:
4350
+ do_binary_op:
4351
+ if (pn->pn_arity == PN_LIST) {
4352
+ JS_ASSERT(pn->pn_count > 2);
4353
+ for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
4354
+ if (!FoldType(cx, pn2, TOK_NUMBER))
4355
+ return JS_FALSE;
4356
+ /* XXX fold only if all operands convert to number */
4357
+ if (pn2->pn_type != TOK_NUMBER)
4358
+ break;
4359
+ }
4360
+ if (!pn2) {
4361
+ JSOp op = pn->pn_op;
4362
+
4363
+ pn2 = pn1->pn_next;
4364
+ pn3 = pn2->pn_next;
4365
+ if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc))
4366
+ return JS_FALSE;
4367
+ while ((pn2 = pn3) != NULL) {
4368
+ pn3 = pn2->pn_next;
4369
+ if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc))
4370
+ return JS_FALSE;
4371
+ }
4372
+ }
4373
+ } else {
4374
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
4375
+ if (!FoldType(cx, pn1, TOK_NUMBER) ||
4376
+ !FoldType(cx, pn2, TOK_NUMBER)) {
4377
+ return JS_FALSE;
4378
+ }
4379
+ if (pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER) {
4380
+ if (!FoldBinaryNumeric(cx, pn->pn_op, pn1, pn2, pn, tc))
4381
+ return JS_FALSE;
4382
+ }
4383
+ }
4384
+ break;
4385
+
4386
+ case TOK_UNARYOP:
4387
+ if (pn1->pn_type == TOK_NUMBER) {
4388
+ jsdouble d;
4389
+ int32 i;
4390
+
4391
+ /* Operate on one numeric constant. */
4392
+ d = pn1->pn_dval;
4393
+ switch (pn->pn_op) {
4394
+ case JSOP_BITNOT:
4395
+ if (!js_DoubleToECMAInt32(cx, d, &i))
4396
+ return JS_FALSE;
4397
+ d = ~i;
4398
+ break;
4399
+
4400
+ case JSOP_NEG:
4401
+ #ifdef HPUX
4402
+ /*
4403
+ * Negation of a zero doesn't produce a negative
4404
+ * zero on HPUX. Perform the operation by bit
4405
+ * twiddling.
4406
+ */
4407
+ JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
4408
+ #else
4409
+ d = -d;
4410
+ #endif
4411
+ break;
4412
+
4413
+ case JSOP_POS:
4414
+ break;
4415
+
4416
+ case JSOP_NOT:
4417
+ pn->pn_type = TOK_PRIMARY;
4418
+ pn->pn_op = (d == 0) ? JSOP_TRUE : JSOP_FALSE;
4419
+ pn->pn_arity = PN_NULLARY;
4420
+ /* FALL THROUGH */
4421
+
4422
+ default:
4423
+ /* Return early to dodge the common TOK_NUMBER code. */
4424
+ return JS_TRUE;
4425
+ }
4426
+ pn->pn_type = TOK_NUMBER;
4427
+ pn->pn_op = JSOP_NUMBER;
4428
+ pn->pn_arity = PN_NULLARY;
4429
+ pn->pn_dval = d;
4430
+ RecycleTree(pn1, tc);
4431
+ }
4432
+ break;
4433
+
4434
+ default:;
4435
+ }
4436
+
4437
+ return JS_TRUE;
4438
+ }