distil 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }