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,3831 @@
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 regular expressions, after Perl.
42
+ */
43
+ #include "jsstddef.h"
44
+ #include <stdlib.h>
45
+ #include <string.h>
46
+ #include "jstypes.h"
47
+ #include "jsarena.h" /* Added by JSIFY */
48
+ #include "jsutil.h" /* Added by JSIFY */
49
+ #include "jsapi.h"
50
+ #include "jsarray.h"
51
+ #include "jsatom.h"
52
+ #include "jscntxt.h"
53
+ #include "jsconfig.h"
54
+ #include "jsfun.h"
55
+ #include "jsgc.h"
56
+ #include "jsinterp.h"
57
+ #include "jslock.h"
58
+ #include "jsnum.h"
59
+ #include "jsobj.h"
60
+ #include "jsopcode.h"
61
+ #include "jsregexp.h"
62
+ #include "jsscan.h"
63
+ #include "jsstr.h"
64
+
65
+ #ifdef XP_MAC
66
+ #include <MacMemory.h>
67
+ #endif
68
+
69
+ #if JS_HAS_REGEXPS
70
+
71
+ /* Note : contiguity of 'simple opcodes' is important for SimpleMatch() */
72
+ typedef enum REOp {
73
+ REOP_EMPTY = 0, /* match rest of input against rest of r.e. */
74
+ REOP_ALT = 1, /* alternative subexpressions in kid and next */
75
+ REOP_SIMPLE_START = 2, /* start of 'simple opcodes' */
76
+ REOP_BOL = 2, /* beginning of input (or line if multiline) */
77
+ REOP_EOL = 3, /* end of input (or line if multiline) */
78
+ REOP_WBDRY = 4, /* match "" at word boundary */
79
+ REOP_WNONBDRY = 5, /* match "" at word non-boundary */
80
+ REOP_DOT = 6, /* stands for any character */
81
+ REOP_DIGIT = 7, /* match a digit char: [0-9] */
82
+ REOP_NONDIGIT = 8, /* match a non-digit char: [^0-9] */
83
+ REOP_ALNUM = 9, /* match an alphanumeric char: [0-9a-z_A-Z] */
84
+ REOP_NONALNUM = 10, /* match a non-alphanumeric char: [^0-9a-z_A-Z] */
85
+ REOP_SPACE = 11, /* match a whitespace char */
86
+ REOP_NONSPACE = 12, /* match a non-whitespace char */
87
+ REOP_BACKREF = 13, /* back-reference (e.g., \1) to a parenthetical */
88
+ REOP_FLAT = 14, /* match a flat string */
89
+ REOP_FLAT1 = 15, /* match a single char */
90
+ REOP_FLATi = 16, /* case-independent REOP_FLAT */
91
+ REOP_FLAT1i = 17, /* case-independent REOP_FLAT1 */
92
+ REOP_UCFLAT1 = 18, /* single Unicode char */
93
+ REOP_UCFLAT1i = 19, /* case-independent REOP_UCFLAT1 */
94
+ REOP_UCFLAT = 20, /* flat Unicode string; len immediate counts chars */
95
+ REOP_UCFLATi = 21, /* case-independent REOP_UCFLAT */
96
+ REOP_CLASS = 22, /* character class with index */
97
+ REOP_NCLASS = 23, /* negated character class with index */
98
+ REOP_SIMPLE_END = 23, /* end of 'simple opcodes' */
99
+ REOP_QUANT = 25, /* quantified atom: atom{1,2} */
100
+ REOP_STAR = 26, /* zero or more occurrences of kid */
101
+ REOP_PLUS = 27, /* one or more occurrences of kid */
102
+ REOP_OPT = 28, /* optional subexpression in kid */
103
+ REOP_LPAREN = 29, /* left paren bytecode: kid is u.num'th sub-regexp */
104
+ REOP_RPAREN = 30, /* right paren bytecode */
105
+ REOP_JUMP = 31, /* for deoptimized closure loops */
106
+ REOP_DOTSTAR = 32, /* optimize .* to use a single opcode */
107
+ REOP_ANCHOR = 33, /* like .* but skips left context to unanchored r.e. */
108
+ REOP_EOLONLY = 34, /* $ not preceded by any pattern */
109
+ REOP_BACKREFi = 37, /* case-independent REOP_BACKREF */
110
+ REOP_LPARENNON = 41, /* non-capturing version of REOP_LPAREN */
111
+ REOP_ASSERT = 43, /* zero width positive lookahead assertion */
112
+ REOP_ASSERT_NOT = 44, /* zero width negative lookahead assertion */
113
+ REOP_ASSERTTEST = 45, /* sentinel at end of assertion child */
114
+ REOP_ASSERTNOTTEST = 46, /* sentinel at end of !assertion child */
115
+ REOP_MINIMALSTAR = 47, /* non-greedy version of * */
116
+ REOP_MINIMALPLUS = 48, /* non-greedy version of + */
117
+ REOP_MINIMALOPT = 49, /* non-greedy version of ? */
118
+ REOP_MINIMALQUANT = 50, /* non-greedy version of {} */
119
+ REOP_ENDCHILD = 51, /* sentinel at end of quantifier child */
120
+ REOP_REPEAT = 52, /* directs execution of greedy quantifier */
121
+ REOP_MINIMALREPEAT = 53, /* directs execution of non-greedy quantifier */
122
+ REOP_ALTPREREQ = 54, /* prerequisite for ALT, either of two chars */
123
+ REOP_ALTPREREQ2 = 55, /* prerequisite for ALT, a char or a class */
124
+ REOP_ENDALT = 56, /* end of final alternate */
125
+ REOP_CONCAT = 57, /* concatenation of terms (parse time only) */
126
+
127
+ REOP_END
128
+ } REOp;
129
+
130
+ #define REOP_IS_SIMPLE(op) ((unsigned)((op) - REOP_SIMPLE_START) < \
131
+ (unsigned)REOP_SIMPLE_END)
132
+
133
+ struct RENode {
134
+ REOp op; /* r.e. op bytecode */
135
+ RENode *next; /* next in concatenation order */
136
+ void *kid; /* first operand */
137
+ union {
138
+ void *kid2; /* second operand */
139
+ jsint num; /* could be a number */
140
+ uint16 parenIndex; /* or a parenthesis index */
141
+ struct { /* or a quantifier range */
142
+ uint16 min;
143
+ uint16 max;
144
+ JSBool greedy;
145
+ } range;
146
+ struct { /* or a character class */
147
+ uint16 startIndex;
148
+ uint16 kidlen; /* length of string at kid, in jschars */
149
+ uint16 bmsize; /* bitmap size, based on max char code */
150
+ uint16 index; /* index into class list */
151
+ JSBool sense;
152
+ } ucclass;
153
+ struct { /* or a literal sequence */
154
+ jschar chr; /* of one character */
155
+ uint16 length; /* or many (via the kid) */
156
+ } flat;
157
+ struct {
158
+ RENode *kid2; /* second operand from ALT */
159
+ jschar ch1; /* match char for ALTPREREQ */
160
+ jschar ch2; /* ditto, or class index for ALTPREREQ2 */
161
+ } altprereq;
162
+ } u;
163
+ };
164
+
165
+ #define RE_IS_LETTER(c) (((c >= 'A') && (c <= 'Z')) || \
166
+ ((c >= 'a') && (c <= 'z')) )
167
+ #define RE_IS_LINE_TERM(c) ((c == '\n') || (c == '\r') || \
168
+ (c == LINE_SEPARATOR) || (c == PARA_SEPARATOR))
169
+
170
+ #define CLASS_CACHE_SIZE 4
171
+
172
+ typedef struct CompilerState {
173
+ JSContext *context;
174
+ JSTokenStream *tokenStream; /* For reporting errors */
175
+ const jschar *cpbegin;
176
+ const jschar *cpend;
177
+ const jschar *cp;
178
+ uint16 flags;
179
+ uint16 parenCount;
180
+ uint16 classCount; /* number of [] encountered */
181
+ uint16 treeDepth; /* maximum depth of parse tree */
182
+ size_t progLength; /* estimated bytecode length */
183
+ RENode *result;
184
+ struct {
185
+ const jschar *start; /* small cache of class strings */
186
+ uint16 length; /* since they're often the same */
187
+ uint16 index;
188
+ } classCache[CLASS_CACHE_SIZE];
189
+ } CompilerState;
190
+
191
+ typedef struct RECapture {
192
+ int32 index; /* start of contents, -1 for empty */
193
+ uint16 length; /* length of capture */
194
+ } RECapture;
195
+
196
+ typedef struct REMatchState {
197
+ const jschar *cp;
198
+ RECapture parens[1]; /* first of 're->parenCount' captures,
199
+ * allocated at end of this struct.
200
+ */
201
+ } REMatchState;
202
+
203
+ struct REBackTrackData;
204
+
205
+ typedef struct REProgState {
206
+ jsbytecode *continue_pc; /* current continuation data */
207
+ jsbytecode continue_op;
208
+ uint16 index; /* progress in text */
209
+ uintN parenSoFar; /* highest indexed paren started */
210
+ union {
211
+ struct {
212
+ uint16 min; /* current quantifier limits */
213
+ uint16 max;
214
+ } quantifier;
215
+ struct {
216
+ size_t top; /* backtrack stack state */
217
+ size_t sz;
218
+ } assertion;
219
+ } u;
220
+ } REProgState;
221
+
222
+ typedef struct REBackTrackData {
223
+ size_t sz; /* size of previous stack entry */
224
+ jsbytecode *backtrack_pc; /* where to backtrack to */
225
+ jsbytecode backtrack_op;
226
+ const jschar *cp; /* index in text of match at backtrack */
227
+ uint16 parenIndex; /* start index of saved paren contents */
228
+ uint16 parenCount; /* # of saved paren contents */
229
+ uint16 saveStateStackTop; /* number of parent states */
230
+ /* saved parent states follow */
231
+ /* saved paren contents follow */
232
+ } REBackTrackData;
233
+
234
+ #define INITIAL_STATESTACK (100)
235
+ #define INITIAL_BACKTRACK (8000)
236
+
237
+ typedef struct REGlobalData {
238
+ JSContext *cx;
239
+ JSRegExp *regexp; /* the RE in execution */
240
+ JSBool ok; /* runtime error (out_of_memory only?) */
241
+ size_t start; /* offset to start at */
242
+ ptrdiff_t skipped; /* chars skipped anchoring this r.e. */
243
+ const jschar *cpbegin, *cpend; /* text base address and limit */
244
+
245
+ REProgState *stateStack; /* stack of state of current parents */
246
+ uint16 stateStackTop;
247
+ uint16 stateStackLimit;
248
+
249
+ REBackTrackData *backTrackStack;/* stack of matched-so-far positions */
250
+ REBackTrackData *backTrackSP;
251
+ size_t backTrackStackSize;
252
+ size_t cursz; /* size of current stack entry */
253
+
254
+ JSArenaPool pool; /* I don't understand but it's faster to
255
+ * use this than to malloc/free the three
256
+ * items that are allocated from this pool
257
+ */
258
+
259
+ } REGlobalData;
260
+
261
+
262
+ /*
263
+ * 1. If IgnoreCase is false, return ch.
264
+ * 2. Let u be ch converted to upper case as if by calling
265
+ * String.prototype.toUpperCase on the one-character string ch.
266
+ * 3. If u does not consist of a single character, return ch.
267
+ * 4. Let cu be u's character.
268
+ * 5. If ch's code point value is greater than or equal to decimal 128 and cu's
269
+ * code point value is less than decimal 128, then return ch.
270
+ * 6. Return cu.
271
+ */
272
+ static jschar
273
+ upcase(jschar ch)
274
+ {
275
+ jschar cu = JS_TOUPPER(ch);
276
+ if (ch >= 128 && cu < 128)
277
+ return ch;
278
+ return cu;
279
+ }
280
+
281
+ static jschar
282
+ downcase(jschar ch)
283
+ {
284
+ jschar cl = JS_TOLOWER(ch);
285
+ if (cl >= 128 && ch < 128)
286
+ return ch;
287
+ return cl;
288
+ }
289
+
290
+ /* Construct and initialize an RENode, returning NULL for out-of-memory */
291
+ static RENode *
292
+ NewRENode(CompilerState *state, REOp op)
293
+ {
294
+ JSContext *cx;
295
+ RENode *ren;
296
+
297
+ cx = state->context;
298
+ JS_ARENA_ALLOCATE_CAST(ren, RENode *, &cx->tempPool, sizeof *ren);
299
+ if (!ren) {
300
+ JS_ReportOutOfMemory(cx);
301
+ return NULL;
302
+ }
303
+ ren->op = op;
304
+ ren->next = NULL;
305
+ ren->kid = NULL;
306
+ return ren;
307
+ }
308
+
309
+ /*
310
+ * Validates and converts hex ascii value.
311
+ */
312
+ static JSBool
313
+ isASCIIHexDigit(jschar c, uintN *digit)
314
+ {
315
+ uintN cv = c;
316
+
317
+ if (cv < '0')
318
+ return JS_FALSE;
319
+ if (cv <= '9') {
320
+ *digit = cv - '0';
321
+ return JS_TRUE;
322
+ }
323
+ cv |= 0x20;
324
+ if (cv >= 'a' && cv <= 'f') {
325
+ *digit = cv - 'a' + 10;
326
+ return JS_TRUE;
327
+ }
328
+ return JS_FALSE;
329
+ }
330
+
331
+
332
+ typedef struct {
333
+ REOp op;
334
+ const jschar *errPos;
335
+ uint16 parenIndex;
336
+ } REOpData;
337
+
338
+
339
+ /*
340
+ * Process the op against the two top operands, reducing them to a single
341
+ * operand in the penultimate slot. Update progLength and treeDepth.
342
+ */
343
+ static JSBool
344
+ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN operandSP)
345
+ {
346
+ RENode *result;
347
+
348
+ switch (opData->op) {
349
+ case REOP_ALT:
350
+ result = NewRENode(state, REOP_ALT);
351
+ if (!result)
352
+ return JS_FALSE;
353
+ result->kid = operandStack[operandSP - 2];
354
+ result->u.kid2 = operandStack[operandSP - 1];
355
+ operandStack[operandSP - 2] = result;
356
+ /*
357
+ * look at both alternates to see if there's a FLAT or a CLASS at
358
+ * the start of each. If so, use a prerequisite match
359
+ */
360
+ ++state->treeDepth;
361
+ if (((RENode *) result->kid)->op == REOP_FLAT &&
362
+ ((RENode *) result->u.kid2)->op == REOP_FLAT &&
363
+ (state->flags & JSREG_FOLD) == 0) {
364
+ result->op = REOP_ALTPREREQ;
365
+ result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr;
366
+ result->u.altprereq.ch2 = ((RENode *) result->u.kid2)->u.flat.chr;
367
+ /* ALTPREREQ, <end>, uch1, uch2, <next>, ...,
368
+ JUMP, <end> ... ENDALT */
369
+ state->progLength += 13;
370
+ }
371
+ else
372
+ if (((RENode *) result->kid)->op == REOP_CLASS &&
373
+ ((RENode *) result->kid)->u.ucclass.index < 256 &&
374
+ ((RENode *) result->u.kid2)->op == REOP_FLAT &&
375
+ (state->flags & JSREG_FOLD) == 0) {
376
+ result->op = REOP_ALTPREREQ2;
377
+ result->u.altprereq.ch1 = ((RENode *) result->u.kid2)->u.flat.chr;
378
+ result->u.altprereq.ch2 = ((RENode *) result->kid)->u.ucclass.index;
379
+ /* ALTPREREQ2, <end>, uch1, uch2, <next>, ...,
380
+ JUMP, <end> ... ENDALT */
381
+ state->progLength += 13;
382
+ }
383
+ else
384
+ if (((RENode *) result->kid)->op == REOP_FLAT &&
385
+ ((RENode *) result->u.kid2)->op == REOP_CLASS &&
386
+ ((RENode *) result->u.kid2)->u.ucclass.index < 256 &&
387
+ (state->flags & JSREG_FOLD) == 0) {
388
+ result->op = REOP_ALTPREREQ2;
389
+ result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr;
390
+ result->u.altprereq.ch2 =
391
+ ((RENode *) result->u.kid2)->u.ucclass.index;
392
+ /* ALTPREREQ2, <end>, uch1, uch2, <next>, ...,
393
+ JUMP, <end> ... ENDALT */
394
+ state->progLength += 13;
395
+ }
396
+ else
397
+ /* ALT, <next>, ..., JUMP, <end> ... ENDALT */
398
+ state->progLength += 7;
399
+ break;
400
+ case REOP_CONCAT:
401
+ result = operandStack[operandSP - 2];
402
+ while (result->next)
403
+ result = result->next;
404
+ result->next = operandStack[operandSP - 1];
405
+ break;
406
+ case REOP_ASSERT:
407
+ case REOP_ASSERT_NOT:
408
+ case REOP_LPARENNON:
409
+ case REOP_LPAREN:
410
+ /* These should have been processed by a close paren. */
411
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
412
+ NULL, JSREPORT_ERROR,
413
+ JSMSG_MISSING_PAREN, opData->errPos);
414
+ return JS_FALSE;
415
+ default:;
416
+ }
417
+ return JS_TRUE;
418
+ }
419
+
420
+ /*
421
+ * Parser forward declarations.
422
+ */
423
+ static JSBool ParseTerm(CompilerState *state);
424
+ static JSBool ParseQuantifier(CompilerState *state);
425
+
426
+ /*
427
+ * Top-down regular expression grammar, based closely on Perl4.
428
+ *
429
+ * regexp: altern A regular expression is one or more
430
+ * altern '|' regexp alternatives separated by vertical bar.
431
+ */
432
+ #define INITIAL_STACK_SIZE 128
433
+
434
+ static JSBool
435
+ ParseRegExp(CompilerState *state)
436
+ {
437
+ uint16 parenIndex;
438
+ RENode *operand;
439
+ REOpData *operatorStack;
440
+ RENode **operandStack;
441
+ REOp op;
442
+ intN i;
443
+ JSBool result = JS_FALSE;
444
+
445
+ intN operatorSP = 0, operatorStackSize = INITIAL_STACK_SIZE;
446
+ intN operandSP = 0, operandStackSize = INITIAL_STACK_SIZE;
447
+
448
+ /* Watch out for empty regexp */
449
+ if (state->cp == state->cpend) {
450
+ state->result = NewRENode(state, REOP_EMPTY);
451
+ return (state->result != NULL);
452
+ }
453
+
454
+ operatorStack = (REOpData *)
455
+ JS_malloc(state->context, sizeof(REOpData) * operatorStackSize);
456
+ if (!operatorStack)
457
+ return JS_FALSE;
458
+
459
+ operandStack = (RENode **)
460
+ JS_malloc(state->context, sizeof(RENode *) * operandStackSize);
461
+ if (!operandStack)
462
+ goto out;
463
+
464
+ while (JS_TRUE) {
465
+ parenIndex = state->parenCount;
466
+ if (state->cp == state->cpend) {
467
+ /*
468
+ * If we are at the end of the regexp and we're short one or more
469
+ * operands, the regexp must have the form /x|/ or some such, with
470
+ * left parentheses making us short more than one operand.
471
+ */
472
+ if (operatorSP >= operandSP) {
473
+ operand = NewRENode(state, REOP_EMPTY);
474
+ if (!operand)
475
+ goto out;
476
+ goto pushOperand;
477
+ }
478
+ } else {
479
+ switch (*state->cp) {
480
+ /* balance '(' */
481
+ case '(': /* balance ')' */
482
+ ++state->cp;
483
+ if (state->cp + 1 < state->cpend &&
484
+ *state->cp == '?' &&
485
+ (state->cp[1] == '=' ||
486
+ state->cp[1] == '!' ||
487
+ state->cp[1] == ':')) {
488
+ switch (state->cp[1]) {
489
+ case '=':
490
+ op = REOP_ASSERT;
491
+ /* ASSERT, <next>, ... ASSERTTEST */
492
+ state->progLength += 4;
493
+ break;
494
+ case '!':
495
+ op = REOP_ASSERT_NOT;
496
+ /* ASSERTNOT, <next>, ... ASSERTNOTTEST */
497
+ state->progLength += 4;
498
+ break;
499
+ default:
500
+ op = REOP_LPARENNON;
501
+ break;
502
+ }
503
+ state->cp += 2;
504
+ } else {
505
+ op = REOP_LPAREN;
506
+ /* LPAREN, <index>, ... RPAREN, <index> */
507
+ state->progLength += 6;
508
+ state->parenCount++;
509
+ if (state->parenCount == 65535) {
510
+ js_ReportCompileErrorNumber(state->context,
511
+ state->tokenStream,
512
+ NULL, JSREPORT_ERROR,
513
+ JSMSG_TOO_MANY_PARENS);
514
+ goto out;
515
+ }
516
+ }
517
+ goto pushOperator;
518
+ case ')':
519
+ /* If there's not a stacked open parenthesis, throw
520
+ * a syntax error.
521
+ */
522
+ for (i = operatorSP - 1; ; i--) {
523
+ if (i < 0) {
524
+ js_ReportCompileErrorNumber(state->context,
525
+ state->tokenStream,
526
+ NULL, JSREPORT_ERROR,
527
+ JSMSG_UNMATCHED_RIGHT_PAREN);
528
+ goto out;
529
+ }
530
+ if (operatorStack[i].op == REOP_ASSERT ||
531
+ operatorStack[i].op == REOP_ASSERT_NOT ||
532
+ operatorStack[i].op == REOP_LPARENNON ||
533
+ operatorStack[i].op == REOP_LPAREN) {
534
+ break;
535
+ }
536
+ }
537
+ /* fall thru... */
538
+ case '|':
539
+ /* Expected an operand before these, so make an empty one */
540
+ operand = NewRENode(state, REOP_EMPTY);
541
+ if (!operand)
542
+ goto out;
543
+ goto pushOperand;
544
+ default:
545
+ if (!ParseTerm(state))
546
+ goto out;
547
+ operand = state->result;
548
+ pushOperand:
549
+ if (operandSP == operandStackSize) {
550
+ operandStackSize += operandStackSize;
551
+ operandStack =
552
+ (RENode **)JS_realloc(state->context, operandStack,
553
+ sizeof(RENode *) * operandStackSize);
554
+ if (!operandStack)
555
+ goto out;
556
+ }
557
+ operandStack[operandSP++] = operand;
558
+ break;
559
+ }
560
+ }
561
+ /* At the end; process remaining operators */
562
+ restartOperator:
563
+ if (state->cp == state->cpend) {
564
+ while (operatorSP) {
565
+ --operatorSP;
566
+ if (!ProcessOp(state, &operatorStack[operatorSP],
567
+ operandStack, operandSP))
568
+ goto out;
569
+ --operandSP;
570
+ }
571
+ JS_ASSERT(operandSP == 1);
572
+ state->result = operandStack[0];
573
+ result = JS_TRUE;
574
+ goto out;
575
+ }
576
+ switch (*state->cp) {
577
+ case '|':
578
+ /* Process any stacked 'concat' operators */
579
+ ++state->cp;
580
+ while (operatorSP &&
581
+ operatorStack[operatorSP - 1].op == REOP_CONCAT) {
582
+ --operatorSP;
583
+ if (!ProcessOp(state, &operatorStack[operatorSP],
584
+ operandStack, operandSP))
585
+ goto out;
586
+ --operandSP;
587
+ }
588
+ op = REOP_ALT;
589
+ goto pushOperator;
590
+
591
+ case ')':
592
+ /* If there's not a stacked open parenthesis,we
593
+ * accept the close as a flat.
594
+ */
595
+ for (i = operatorSP - 1; ; i--) {
596
+ if (i < 0) {
597
+ js_ReportCompileErrorNumber(state->context,
598
+ state->tokenStream,
599
+ NULL, JSREPORT_ERROR,
600
+ JSMSG_UNMATCHED_RIGHT_PAREN);
601
+ goto out;
602
+ }
603
+ if (operatorStack[i].op == REOP_ASSERT ||
604
+ operatorStack[i].op == REOP_ASSERT_NOT ||
605
+ operatorStack[i].op == REOP_LPARENNON ||
606
+ operatorStack[i].op == REOP_LPAREN) {
607
+ break;
608
+ }
609
+ }
610
+ ++state->cp;
611
+ /* process everything on the stack until the open */
612
+ while (JS_TRUE) {
613
+ JS_ASSERT(operatorSP);
614
+ --operatorSP;
615
+ switch (operatorStack[operatorSP].op) {
616
+ case REOP_ASSERT:
617
+ case REOP_ASSERT_NOT:
618
+ case REOP_LPAREN:
619
+ operand = NewRENode(state, operatorStack[operatorSP].op);
620
+ if (!operand)
621
+ goto out;
622
+ operand->u.parenIndex =
623
+ operatorStack[operatorSP].parenIndex;
624
+ JS_ASSERT(operandSP);
625
+ operand->kid = operandStack[operandSP - 1];
626
+ operandStack[operandSP - 1] = operand;
627
+ ++state->treeDepth;
628
+ /* fall thru... */
629
+ case REOP_LPARENNON:
630
+ state->result = operandStack[operandSP - 1];
631
+ if (!ParseQuantifier(state))
632
+ goto out;
633
+ operandStack[operandSP - 1] = state->result;
634
+ goto restartOperator;
635
+ default:
636
+ if (!ProcessOp(state, &operatorStack[operatorSP],
637
+ operandStack, operandSP))
638
+ goto out;
639
+ --operandSP;
640
+ break;
641
+ }
642
+ }
643
+ break;
644
+ case '+':
645
+ case '*':
646
+ case '?':
647
+ case '{':
648
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
649
+ NULL, JSREPORT_ERROR,
650
+ JSMSG_BAD_QUANTIFIER, state->cp);
651
+ result = JS_FALSE;
652
+ goto out;
653
+ default:
654
+ /* Anything else is the start of the next term */
655
+ op = REOP_CONCAT;
656
+ pushOperator:
657
+ if (operatorSP == operatorStackSize) {
658
+ operatorStackSize += operatorStackSize;
659
+ operatorStack =
660
+ (REOpData *)JS_realloc(state->context, operatorStack,
661
+ sizeof(REOpData) * operatorStackSize);
662
+ if (!operatorStack)
663
+ goto out;
664
+ }
665
+ operatorStack[operatorSP].op = op;
666
+ operatorStack[operatorSP].errPos = state->cp;
667
+ operatorStack[operatorSP++].parenIndex = parenIndex;
668
+ break;
669
+ }
670
+ }
671
+ out:
672
+ if (operatorStack)
673
+ JS_free(state->context, operatorStack);
674
+ if (operandStack)
675
+ JS_free(state->context, operandStack);
676
+ return result;
677
+ }
678
+
679
+ /*
680
+ * Hack two bits in CompilerState.flags, for use within FindParenCount to flag
681
+ * its being on the stack, and to propagate errors to its callers.
682
+ */
683
+ #define JSREG_FIND_PAREN_COUNT 0x8000
684
+ #define JSREG_FIND_PAREN_ERROR 0x4000
685
+
686
+ /*
687
+ * Magic return value from FindParenCount and GetDecimalValue, to indicate
688
+ * overflow beyond GetDecimalValue's max parameter, or a computed maximum if
689
+ * its findMax parameter is non-null.
690
+ */
691
+ #define OVERFLOW_VALUE ((uintN)-1)
692
+
693
+ static uintN
694
+ FindParenCount(CompilerState *state)
695
+ {
696
+ CompilerState temp;
697
+ int i;
698
+
699
+ if (state->flags & JSREG_FIND_PAREN_COUNT)
700
+ return OVERFLOW_VALUE;
701
+
702
+ /*
703
+ * Copy state into temp, flag it so we never report an invalid backref,
704
+ * and reset its members to parse the entire regexp. This is obviously
705
+ * suboptimal, but GetDecimalValue calls us only if a backref appears to
706
+ * refer to a forward parenthetical, which is rare.
707
+ */
708
+ temp = *state;
709
+ temp.flags |= JSREG_FIND_PAREN_COUNT;
710
+ temp.cp = temp.cpbegin;
711
+ temp.parenCount = 0;
712
+ temp.classCount = 0;
713
+ temp.progLength = 0;
714
+ temp.treeDepth = 0;
715
+ for (i = 0; i < CLASS_CACHE_SIZE; i++)
716
+ temp.classCache[i].start = NULL;
717
+
718
+ if (!ParseRegExp(&temp)) {
719
+ state->flags |= JSREG_FIND_PAREN_ERROR;
720
+ return OVERFLOW_VALUE;
721
+ }
722
+ return temp.parenCount;
723
+ }
724
+
725
+ /*
726
+ * Extract and return a decimal value at state->cp. The initial character c
727
+ * has already been read. Return OVERFLOW_VALUE if the result exceeds max.
728
+ * Callers who pass a non-null findMax should test JSREG_FIND_PAREN_ERROR in
729
+ * state->flags to discover whether an error occurred under findMax.
730
+ */
731
+ static uintN
732
+ GetDecimalValue(jschar c, uintN max, uintN (*findMax)(CompilerState *state),
733
+ CompilerState *state)
734
+ {
735
+ uintN value = JS7_UNDEC(c);
736
+ JSBool overflow = (value > max && (!findMax || value > findMax(state)));
737
+
738
+ /* The following restriction allows simpler overflow checks. */
739
+ JS_ASSERT(max <= ((uintN)-1 - 9) / 10);
740
+ while (state->cp < state->cpend) {
741
+ c = *state->cp;
742
+ if (!JS7_ISDEC(c))
743
+ break;
744
+ value = 10 * value + JS7_UNDEC(c);
745
+ if (!overflow && value > max && (!findMax || value > findMax(state)))
746
+ overflow = JS_TRUE;
747
+ ++state->cp;
748
+ }
749
+ return overflow ? OVERFLOW_VALUE : value;
750
+ }
751
+
752
+ /*
753
+ * Calculate the total size of the bitmap required for a class expression.
754
+ */
755
+ static JSBool
756
+ CalculateBitmapSize(CompilerState *state, RENode *target, const jschar *src,
757
+ const jschar *end)
758
+ {
759
+ uintN max = 0;
760
+ JSBool inRange = JS_FALSE;
761
+ jschar c, rangeStart = 0;
762
+ uintN n, digit, nDigits, i;
763
+
764
+ target->u.ucclass.bmsize = 0;
765
+ target->u.ucclass.sense = JS_TRUE;
766
+
767
+ if (src == end)
768
+ return JS_TRUE;
769
+
770
+ if (*src == '^') {
771
+ ++src;
772
+ target->u.ucclass.sense = JS_FALSE;
773
+ }
774
+
775
+ while (src != end) {
776
+ uintN localMax = 0;
777
+ switch (*src) {
778
+ case '\\':
779
+ ++src;
780
+ c = *src++;
781
+ switch (c) {
782
+ case 'b':
783
+ localMax = 0x8;
784
+ break;
785
+ case 'f':
786
+ localMax = 0xC;
787
+ break;
788
+ case 'n':
789
+ localMax = 0xA;
790
+ break;
791
+ case 'r':
792
+ localMax = 0xD;
793
+ break;
794
+ case 't':
795
+ localMax = 0x9;
796
+ break;
797
+ case 'v':
798
+ localMax = 0xB;
799
+ break;
800
+ case 'c':
801
+ if (src + 1 < end && RE_IS_LETTER(src[1]))
802
+ localMax = (jschar) (*src++ & 0x1F);
803
+ else
804
+ localMax = '\\';
805
+ break;
806
+ case 'x':
807
+ nDigits = 2;
808
+ goto lexHex;
809
+ case 'u':
810
+ nDigits = 4;
811
+ lexHex:
812
+ n = 0;
813
+ for (i = 0; (i < nDigits) && (src < end); i++) {
814
+ c = *src++;
815
+ if (!isASCIIHexDigit(c, &digit)) {
816
+ /*
817
+ * Back off to accepting the original
818
+ *'\' as a literal.
819
+ */
820
+ src -= i + 1;
821
+ n = '\\';
822
+ break;
823
+ }
824
+ n = (n << 4) | digit;
825
+ }
826
+ localMax = n;
827
+ break;
828
+ case 'd':
829
+ if (inRange) {
830
+ JS_ReportErrorNumber(state->context,
831
+ js_GetErrorMessage, NULL,
832
+ JSMSG_BAD_CLASS_RANGE);
833
+ return JS_FALSE;
834
+ }
835
+ localMax = '9';
836
+ break;
837
+ case 'D':
838
+ case 's':
839
+ case 'S':
840
+ case 'w':
841
+ case 'W':
842
+ if (inRange) {
843
+ JS_ReportErrorNumber(state->context,
844
+ js_GetErrorMessage, NULL,
845
+ JSMSG_BAD_CLASS_RANGE);
846
+ return JS_FALSE;
847
+ }
848
+ target->u.ucclass.bmsize = 65535;
849
+ return JS_TRUE;
850
+ case '0':
851
+ case '1':
852
+ case '2':
853
+ case '3':
854
+ case '4':
855
+ case '5':
856
+ case '6':
857
+ case '7':
858
+ /*
859
+ * This is a non-ECMA extension - decimal escapes (in this
860
+ * case, octal!) are supposed to be an error inside class
861
+ * ranges, but supported here for backwards compatibility.
862
+ *
863
+ */
864
+ n = JS7_UNDEC(c);
865
+ c = *src;
866
+ if ('0' <= c && c <= '7') {
867
+ src++;
868
+ n = 8 * n + JS7_UNDEC(c);
869
+ c = *src;
870
+ if ('0' <= c && c <= '7') {
871
+ src++;
872
+ i = 8 * n + JS7_UNDEC(c);
873
+ if (i <= 0377)
874
+ n = i;
875
+ else
876
+ src--;
877
+ }
878
+ }
879
+ localMax = n;
880
+ break;
881
+
882
+ default:
883
+ localMax = c;
884
+ break;
885
+ }
886
+ break;
887
+ default:
888
+ localMax = *src++;
889
+ break;
890
+ }
891
+ if (inRange) {
892
+ if (rangeStart > localMax) {
893
+ JS_ReportErrorNumber(state->context,
894
+ js_GetErrorMessage, NULL,
895
+ JSMSG_BAD_CLASS_RANGE);
896
+ return JS_FALSE;
897
+ }
898
+ inRange = JS_FALSE;
899
+ } else {
900
+ if (src < end - 1) {
901
+ if (*src == '-') {
902
+ ++src;
903
+ inRange = JS_TRUE;
904
+ rangeStart = (jschar)localMax;
905
+ continue;
906
+ }
907
+ }
908
+ }
909
+ if (state->flags & JSREG_FOLD) {
910
+ c = JS_MAX(upcase((jschar)localMax), downcase((jschar)localMax));
911
+ if (c > localMax)
912
+ localMax = c;
913
+ }
914
+ if (localMax > max)
915
+ max = localMax;
916
+ }
917
+ target->u.ucclass.bmsize = max;
918
+ return JS_TRUE;
919
+ }
920
+
921
+ /*
922
+ * item: assertion An item is either an assertion or
923
+ * quantatom a quantified atom.
924
+ *
925
+ * assertion: '^' Assertions match beginning of string
926
+ * (or line if the class static property
927
+ * RegExp.multiline is true).
928
+ * '$' End of string (or line if the class
929
+ * static property RegExp.multiline is
930
+ * true).
931
+ * '\b' Word boundary (between \w and \W).
932
+ * '\B' Word non-boundary.
933
+ *
934
+ * quantatom: atom An unquantified atom.
935
+ * quantatom '{' n ',' m '}'
936
+ * Atom must occur between n and m times.
937
+ * quantatom '{' n ',' '}' Atom must occur at least n times.
938
+ * quantatom '{' n '}' Atom must occur exactly n times.
939
+ * quantatom '*' Zero or more times (same as {0,}).
940
+ * quantatom '+' One or more times (same as {1,}).
941
+ * quantatom '?' Zero or one time (same as {0,1}).
942
+ *
943
+ * any of which can be optionally followed by '?' for ungreedy
944
+ *
945
+ * atom: '(' regexp ')' A parenthesized regexp (what matched
946
+ * can be addressed using a backreference,
947
+ * see '\' n below).
948
+ * '.' Matches any char except '\n'.
949
+ * '[' classlist ']' A character class.
950
+ * '[' '^' classlist ']' A negated character class.
951
+ * '\f' Form Feed.
952
+ * '\n' Newline (Line Feed).
953
+ * '\r' Carriage Return.
954
+ * '\t' Horizontal Tab.
955
+ * '\v' Vertical Tab.
956
+ * '\d' A digit (same as [0-9]).
957
+ * '\D' A non-digit.
958
+ * '\w' A word character, [0-9a-z_A-Z].
959
+ * '\W' A non-word character.
960
+ * '\s' A whitespace character, [ \b\f\n\r\t\v].
961
+ * '\S' A non-whitespace character.
962
+ * '\' n A backreference to the nth (n decimal
963
+ * and positive) parenthesized expression.
964
+ * '\' octal An octal escape sequence (octal must be
965
+ * two or three digits long, unless it is
966
+ * 0 for the null character).
967
+ * '\x' hex A hex escape (hex must be two digits).
968
+ * '\u' unicode A unicode escape (must be four digits).
969
+ * '\c' ctrl A control character, ctrl is a letter.
970
+ * '\' literalatomchar Any character except one of the above
971
+ * that follow '\' in an atom.
972
+ * otheratomchar Any character not first among the other
973
+ * atom right-hand sides.
974
+ */
975
+ static JSBool
976
+ ParseTerm(CompilerState *state)
977
+ {
978
+ jschar c = *state->cp++;
979
+ uintN nDigits;
980
+ uintN num, tmp, n, i;
981
+ const jschar *termStart;
982
+
983
+ switch (c) {
984
+ /* assertions and atoms */
985
+ case '^':
986
+ state->result = NewRENode(state, REOP_BOL);
987
+ if (!state->result)
988
+ return JS_FALSE;
989
+ state->progLength++;
990
+ return JS_TRUE;
991
+ case '$':
992
+ state->result = NewRENode(state, REOP_EOL);
993
+ if (!state->result)
994
+ return JS_FALSE;
995
+ state->progLength++;
996
+ return JS_TRUE;
997
+ case '\\':
998
+ if (state->cp >= state->cpend) {
999
+ /* a trailing '\' is an error */
1000
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
1001
+ NULL, JSREPORT_ERROR,
1002
+ JSMSG_TRAILING_SLASH);
1003
+ return JS_FALSE;
1004
+ }
1005
+ c = *state->cp++;
1006
+ switch (c) {
1007
+ /* assertion escapes */
1008
+ case 'b' :
1009
+ state->result = NewRENode(state, REOP_WBDRY);
1010
+ if (!state->result)
1011
+ return JS_FALSE;
1012
+ state->progLength++;
1013
+ return JS_TRUE;
1014
+ case 'B':
1015
+ state->result = NewRENode(state, REOP_WNONBDRY);
1016
+ if (!state->result)
1017
+ return JS_FALSE;
1018
+ state->progLength++;
1019
+ return JS_TRUE;
1020
+ /* Decimal escape */
1021
+ case '0':
1022
+ if (JS_HAS_STRICT_OPTION(state->context)) {
1023
+ if (!js_ReportCompileErrorNumber(state->context,
1024
+ state->tokenStream,
1025
+ NULL,
1026
+ JSREPORT_WARNING |
1027
+ JSREPORT_STRICT,
1028
+ JSMSG_INVALID_BACKREF)) {
1029
+ return JS_FALSE;
1030
+ }
1031
+ c = 0;
1032
+ } else {
1033
+ doOctal:
1034
+ num = 0;
1035
+ while (state->cp < state->cpend) {
1036
+ c = *state->cp;
1037
+ if (c < '0' || '7' < c)
1038
+ break;
1039
+ state->cp++;
1040
+ tmp = 8 * num + (uintN)JS7_UNDEC(c);
1041
+ if (tmp > 0377)
1042
+ break;
1043
+ num = tmp;
1044
+ }
1045
+ c = (jschar)num;
1046
+ }
1047
+ doFlat:
1048
+ state->result = NewRENode(state, REOP_FLAT);
1049
+ if (!state->result)
1050
+ return JS_FALSE;
1051
+ state->result->u.flat.chr = c;
1052
+ state->result->u.flat.length = 1;
1053
+ state->progLength += 3;
1054
+ break;
1055
+ case '1':
1056
+ case '2':
1057
+ case '3':
1058
+ case '4':
1059
+ case '5':
1060
+ case '6':
1061
+ case '7':
1062
+ case '8':
1063
+ case '9':
1064
+ termStart = state->cp - 1;
1065
+ num = GetDecimalValue(c, state->parenCount, FindParenCount, state);
1066
+ if (state->flags & JSREG_FIND_PAREN_ERROR)
1067
+ return JS_FALSE;
1068
+ if (num == OVERFLOW_VALUE) {
1069
+ if (!JS_HAS_STRICT_OPTION(state->context)) {
1070
+ state->cp = termStart;
1071
+ goto doOctal;
1072
+ }
1073
+ if (!js_ReportCompileErrorNumber(state->context,
1074
+ state->tokenStream,
1075
+ NULL,
1076
+ JSREPORT_WARNING |
1077
+ JSREPORT_STRICT,
1078
+ (c >= '8')
1079
+ ? JSMSG_INVALID_BACKREF
1080
+ : JSMSG_BAD_BACKREF)) {
1081
+ return JS_FALSE;
1082
+ }
1083
+ num = 0x10000;
1084
+ }
1085
+ JS_ASSERT(1 <= num && num <= 0x10000);
1086
+ state->result = NewRENode(state, REOP_BACKREF);
1087
+ if (!state->result)
1088
+ return JS_FALSE;
1089
+ state->result->u.parenIndex = num - 1;
1090
+ state->progLength += 3;
1091
+ break;
1092
+ /* Control escape */
1093
+ case 'f':
1094
+ c = 0xC;
1095
+ goto doFlat;
1096
+ case 'n':
1097
+ c = 0xA;
1098
+ goto doFlat;
1099
+ case 'r':
1100
+ c = 0xD;
1101
+ goto doFlat;
1102
+ case 't':
1103
+ c = 0x9;
1104
+ goto doFlat;
1105
+ case 'v':
1106
+ c = 0xB;
1107
+ goto doFlat;
1108
+ /* Control letter */
1109
+ case 'c':
1110
+ if (state->cp + 1 < state->cpend && RE_IS_LETTER(state->cp[1])) {
1111
+ c = (jschar) (*state->cp++ & 0x1F);
1112
+ } else {
1113
+ /* back off to accepting the original '\' as a literal */
1114
+ --state->cp;
1115
+ c = '\\';
1116
+ }
1117
+ goto doFlat;
1118
+ /* HexEscapeSequence */
1119
+ case 'x':
1120
+ nDigits = 2;
1121
+ goto lexHex;
1122
+ /* UnicodeEscapeSequence */
1123
+ case 'u':
1124
+ nDigits = 4;
1125
+ lexHex:
1126
+ n = 0;
1127
+ for (i = 0; i < nDigits && state->cp < state->cpend; i++) {
1128
+ uintN digit;
1129
+ c = *state->cp++;
1130
+ if (!isASCIIHexDigit(c, &digit)) {
1131
+ /*
1132
+ * back off to accepting the original
1133
+ * 'u' or 'x' as a literal
1134
+ */
1135
+ state->cp -= i + 2;
1136
+ n = *state->cp++;
1137
+ break;
1138
+ }
1139
+ n = (n << 4) | digit;
1140
+ }
1141
+ c = (jschar) n;
1142
+ goto doFlat;
1143
+ /* Character class escapes */
1144
+ case 'd':
1145
+ state->result = NewRENode(state, REOP_DIGIT);
1146
+ doSimple:
1147
+ if (!state->result)
1148
+ return JS_FALSE;
1149
+ state->progLength++;
1150
+ break;
1151
+ case 'D':
1152
+ state->result = NewRENode(state, REOP_NONDIGIT);
1153
+ goto doSimple;
1154
+ case 's':
1155
+ state->result = NewRENode(state, REOP_SPACE);
1156
+ goto doSimple;
1157
+ case 'S':
1158
+ state->result = NewRENode(state, REOP_NONSPACE);
1159
+ goto doSimple;
1160
+ case 'w':
1161
+ state->result = NewRENode(state, REOP_ALNUM);
1162
+ goto doSimple;
1163
+ case 'W':
1164
+ state->result = NewRENode(state, REOP_NONALNUM);
1165
+ goto doSimple;
1166
+ /* IdentityEscape */
1167
+ default:
1168
+ state->result = NewRENode(state, REOP_FLAT);
1169
+ if (!state->result)
1170
+ return JS_FALSE;
1171
+ state->result->u.flat.chr = c;
1172
+ state->result->u.flat.length = 1;
1173
+ state->result->kid = (void *) (state->cp - 1);
1174
+ state->progLength += 3;
1175
+ break;
1176
+ }
1177
+ break;
1178
+ case '[':
1179
+ state->result = NewRENode(state, REOP_CLASS);
1180
+ if (!state->result)
1181
+ return JS_FALSE;
1182
+ termStart = state->cp;
1183
+ state->result->u.ucclass.startIndex = termStart - state->cpbegin;
1184
+ while (JS_TRUE) {
1185
+ if (state->cp == state->cpend) {
1186
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
1187
+ NULL, JSREPORT_ERROR,
1188
+ JSMSG_UNTERM_CLASS, termStart);
1189
+ return JS_FALSE;
1190
+ }
1191
+ if (*state->cp == '\\') {
1192
+ state->cp++;
1193
+ } else {
1194
+ if (*state->cp == ']') {
1195
+ state->result->u.ucclass.kidlen = state->cp - termStart;
1196
+ break;
1197
+ }
1198
+ }
1199
+ state->cp++;
1200
+ }
1201
+ for (i = 0; i < CLASS_CACHE_SIZE; i++) {
1202
+ if (!state->classCache[i].start) {
1203
+ state->classCache[i].start = termStart;
1204
+ state->classCache[i].length = state->result->u.ucclass.kidlen;
1205
+ state->classCache[i].index = state->classCount;
1206
+ break;
1207
+ }
1208
+ if (state->classCache[i].length ==
1209
+ state->result->u.ucclass.kidlen) {
1210
+ for (n = 0; ; n++) {
1211
+ if (n == state->classCache[i].length) {
1212
+ state->result->u.ucclass.index =
1213
+ state->classCache[i].index;
1214
+ goto claim;
1215
+ }
1216
+ if (state->classCache[i].start[n] != termStart[n])
1217
+ break;
1218
+ }
1219
+ }
1220
+ }
1221
+ state->result->u.ucclass.index = state->classCount++;
1222
+ claim:
1223
+ /*
1224
+ * Call CalculateBitmapSize now as we want any errors it finds
1225
+ * to be reported during the parse phase, not at execution.
1226
+ */
1227
+ if (!CalculateBitmapSize(state, state->result, termStart, state->cp++))
1228
+ return JS_FALSE;
1229
+ state->progLength += 3; /* CLASS, <index> */
1230
+ break;
1231
+
1232
+ case '.':
1233
+ state->result = NewRENode(state, REOP_DOT);
1234
+ goto doSimple;
1235
+ case '*':
1236
+ case '+':
1237
+ case '?':
1238
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
1239
+ NULL, JSREPORT_ERROR,
1240
+ JSMSG_BAD_QUANTIFIER, state->cp - 1);
1241
+ return JS_FALSE;
1242
+ default:
1243
+ state->result = NewRENode(state, REOP_FLAT);
1244
+ if (!state->result)
1245
+ return JS_FALSE;
1246
+ state->result->u.flat.chr = c;
1247
+ state->result->u.flat.length = 1;
1248
+ state->result->kid = (void *) (state->cp - 1);
1249
+ state->progLength += 3;
1250
+ break;
1251
+ }
1252
+ return ParseQuantifier(state);
1253
+ }
1254
+
1255
+ static JSBool
1256
+ ParseQuantifier(CompilerState *state)
1257
+ {
1258
+ RENode *term;
1259
+ term = state->result;
1260
+ if (state->cp < state->cpend) {
1261
+ switch (*state->cp) {
1262
+ case '+':
1263
+ state->result = NewRENode(state, REOP_QUANT);
1264
+ if (!state->result)
1265
+ return JS_FALSE;
1266
+ state->result->u.range.min = 1;
1267
+ state->result->u.range.max = (uint16)-1;
1268
+ /* <PLUS>, <next> ... <ENDCHILD> */
1269
+ state->progLength += 4;
1270
+ goto quantifier;
1271
+ case '*':
1272
+ state->result = NewRENode(state, REOP_QUANT);
1273
+ if (!state->result)
1274
+ return JS_FALSE;
1275
+ state->result->u.range.min = 0;
1276
+ state->result->u.range.max = (uint16)-1;
1277
+ /* <STAR>, <next> ... <ENDCHILD> */
1278
+ state->progLength += 4;
1279
+ goto quantifier;
1280
+ case '?':
1281
+ state->result = NewRENode(state, REOP_QUANT);
1282
+ if (!state->result)
1283
+ return JS_FALSE;
1284
+ state->result->u.range.min = 0;
1285
+ state->result->u.range.max = 1;
1286
+ /* <OPT>, <next> ... <ENDCHILD> */
1287
+ state->progLength += 4;
1288
+ goto quantifier;
1289
+ case '{': /* balance '}' */
1290
+ {
1291
+ intN err;
1292
+ uintN min, max;
1293
+ jschar c;
1294
+ const jschar *errp = state->cp++;
1295
+
1296
+ c = *state->cp;
1297
+ if (JS7_ISDEC(c)) {
1298
+ ++state->cp;
1299
+ min = GetDecimalValue(c, 0xFFFF, NULL, state);
1300
+ c = *state->cp;
1301
+
1302
+ if (min == OVERFLOW_VALUE) {
1303
+ err = JSMSG_MIN_TOO_BIG;
1304
+ goto quantError;
1305
+ }
1306
+ if (c == ',') {
1307
+ c = *++state->cp;
1308
+ if (JS7_ISDEC(c)) {
1309
+ ++state->cp;
1310
+ max = GetDecimalValue(c, 0xFFFF, NULL, state);
1311
+ c = *state->cp;
1312
+ if (max == OVERFLOW_VALUE) {
1313
+ err = JSMSG_MAX_TOO_BIG;
1314
+ goto quantError;
1315
+ }
1316
+ if (min > max) {
1317
+ err = JSMSG_OUT_OF_ORDER;
1318
+ goto quantError;
1319
+ }
1320
+ } else {
1321
+ max = (uintN)-1;
1322
+ }
1323
+ } else {
1324
+ max = min;
1325
+ }
1326
+ if (c == '}') {
1327
+ state->result = NewRENode(state, REOP_QUANT);
1328
+ if (!state->result)
1329
+ return JS_FALSE;
1330
+ state->result->u.range.min = min;
1331
+ state->result->u.range.max = max;
1332
+ /* QUANT, <min>, <max>, <next> ... <ENDCHILD> */
1333
+ state->progLength += 8;
1334
+ goto quantifier;
1335
+ }
1336
+ }
1337
+ state->cp = errp;
1338
+ return JS_TRUE;
1339
+ quantError:
1340
+ js_ReportCompileErrorNumber(state->context,
1341
+ state->tokenStream,
1342
+ NULL, JSREPORT_ERROR,
1343
+ err, errp);
1344
+ return JS_FALSE;
1345
+ }
1346
+ }
1347
+ }
1348
+ return JS_TRUE;
1349
+
1350
+ quantifier:
1351
+ ++state->treeDepth;
1352
+ ++state->cp;
1353
+ state->result->kid = term;
1354
+ if (state->cp < state->cpend && *state->cp == '?') {
1355
+ ++state->cp;
1356
+ state->result->u.range.greedy = JS_FALSE;
1357
+ }
1358
+ else
1359
+ state->result->u.range.greedy = JS_TRUE;
1360
+ return JS_TRUE;
1361
+ }
1362
+
1363
+ #define CHECK_OFFSET(diff) (JS_ASSERT(((diff) >= -32768) && ((diff) <= 32767)))
1364
+ #define SET_OFFSET(pc,off) ((pc)[0] = JUMP_OFFSET_HI(off), \
1365
+ (pc)[1] = JUMP_OFFSET_LO(off))
1366
+ #define GET_OFFSET(pc) ((int16)(((pc)[0] << 8) | (pc)[1]))
1367
+ #define OFFSET_LEN (2)
1368
+ #define GET_ARG(pc) GET_OFFSET(pc)
1369
+ #define SET_ARG(pc,arg) SET_OFFSET(pc,arg)
1370
+ #define ARG_LEN OFFSET_LEN
1371
+
1372
+ /*
1373
+ * Recursively generate bytecode for the tree rooted at t. Iteratively.
1374
+ */
1375
+
1376
+ typedef struct {
1377
+ RENode *nextAlt;
1378
+ jsbytecode *nextAltFixup, *nextTermFixup, *endTermFixup;
1379
+ RENode *continueNode;
1380
+ REOp continueOp;
1381
+ } EmitStateStackEntry;
1382
+
1383
+ static jsbytecode *
1384
+ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
1385
+ jsbytecode *pc, RENode *t)
1386
+ {
1387
+ ptrdiff_t diff;
1388
+ RECharSet *charSet;
1389
+ EmitStateStackEntry *emitStateSP, *emitStateStack = NULL;
1390
+ REOp op;
1391
+
1392
+ if (treeDepth) {
1393
+ emitStateStack =
1394
+ (EmitStateStackEntry *)JS_malloc(state->context,
1395
+ sizeof(EmitStateStackEntry) *
1396
+ treeDepth);
1397
+ if (!emitStateStack)
1398
+ return NULL;
1399
+ }
1400
+ emitStateSP = emitStateStack;
1401
+ op = t->op;
1402
+
1403
+ while (JS_TRUE) {
1404
+ *pc++ = op;
1405
+ switch (op) {
1406
+ case REOP_EMPTY:
1407
+ --pc;
1408
+ break;
1409
+
1410
+ case REOP_ALTPREREQ2:
1411
+ case REOP_ALTPREREQ:
1412
+ JS_ASSERT(emitStateSP);
1413
+ emitStateSP->endTermFixup = pc;
1414
+ pc += OFFSET_LEN;
1415
+ SET_ARG(pc, t->u.altprereq.ch1);
1416
+ pc += ARG_LEN;
1417
+ SET_ARG(pc, t->u.altprereq.ch2);
1418
+ pc += ARG_LEN;
1419
+
1420
+ emitStateSP->nextAltFixup = pc; /* address of next alternate */
1421
+ pc += OFFSET_LEN;
1422
+
1423
+ emitStateSP->continueNode = t;
1424
+ emitStateSP->continueOp = REOP_JUMP;
1425
+ ++emitStateSP;
1426
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1427
+ t = (RENode *) t->kid;
1428
+ op = t->op;
1429
+ continue;
1430
+
1431
+ case REOP_JUMP:
1432
+ emitStateSP->nextTermFixup = pc; /* address of following term */
1433
+ pc += OFFSET_LEN;
1434
+ diff = pc - emitStateSP->nextAltFixup;
1435
+ CHECK_OFFSET(diff);
1436
+ SET_OFFSET(emitStateSP->nextAltFixup, diff);
1437
+ emitStateSP->continueOp = REOP_ENDALT;
1438
+ ++emitStateSP;
1439
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1440
+ t = (RENode *) t->u.kid2;
1441
+ op = t->op;
1442
+ continue;
1443
+
1444
+ case REOP_ENDALT:
1445
+ diff = pc - emitStateSP->nextTermFixup;
1446
+ CHECK_OFFSET(diff);
1447
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
1448
+ if (t->op != REOP_ALT) {
1449
+ diff = pc - emitStateSP->endTermFixup;
1450
+ CHECK_OFFSET(diff);
1451
+ SET_OFFSET(emitStateSP->endTermFixup, diff);
1452
+ }
1453
+ break;
1454
+
1455
+ case REOP_ALT:
1456
+ JS_ASSERT(emitStateSP);
1457
+ emitStateSP->nextAltFixup = pc; /* address of pointer to next alternate */
1458
+ pc += OFFSET_LEN;
1459
+ emitStateSP->continueNode = t;
1460
+ emitStateSP->continueOp = REOP_JUMP;
1461
+ ++emitStateSP;
1462
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1463
+ t = (RENode *) t->kid;
1464
+ op = t->op;
1465
+ continue;
1466
+
1467
+ case REOP_FLAT:
1468
+ /*
1469
+ * Consecutize FLAT's if possible.
1470
+ */
1471
+ if (t->kid) {
1472
+ while (t->next &&
1473
+ t->next->op == REOP_FLAT &&
1474
+ (jschar*)t->kid + t->u.flat.length ==
1475
+ (jschar*)t->next->kid) {
1476
+ t->u.flat.length += t->next->u.flat.length;
1477
+ t->next = t->next->next;
1478
+ }
1479
+ }
1480
+ if (t->kid && (t->u.flat.length > 1)) {
1481
+ if (state->flags & JSREG_FOLD)
1482
+ pc[-1] = REOP_FLATi;
1483
+ else
1484
+ pc[-1] = REOP_FLAT;
1485
+ SET_ARG(pc, (jschar *)t->kid - state->cpbegin);
1486
+ pc += ARG_LEN;
1487
+ SET_ARG(pc, t->u.flat.length);
1488
+ pc += ARG_LEN;
1489
+ } else if (t->u.flat.chr < 256) {
1490
+ if (state->flags & JSREG_FOLD)
1491
+ pc[-1] = REOP_FLAT1i;
1492
+ else
1493
+ pc[-1] = REOP_FLAT1;
1494
+ *pc++ = (jsbytecode) t->u.flat.chr;
1495
+ } else {
1496
+ if (state->flags & JSREG_FOLD)
1497
+ pc[-1] = REOP_UCFLAT1i;
1498
+ else
1499
+ pc[-1] = REOP_UCFLAT1;
1500
+ SET_ARG(pc, t->u.flat.chr);
1501
+ pc += ARG_LEN;
1502
+ }
1503
+ break;
1504
+
1505
+ case REOP_LPAREN:
1506
+ JS_ASSERT(emitStateSP);
1507
+ SET_ARG(pc, t->u.parenIndex);
1508
+ pc += ARG_LEN;
1509
+ emitStateSP->continueNode = t;
1510
+ emitStateSP->continueOp = REOP_RPAREN;
1511
+ ++emitStateSP;
1512
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1513
+ t = (RENode *) t->kid;
1514
+ op = t->op;
1515
+ continue;
1516
+ case REOP_RPAREN:
1517
+ SET_ARG(pc, t->u.parenIndex);
1518
+ pc += ARG_LEN;
1519
+ break;
1520
+
1521
+ case REOP_BACKREF:
1522
+ SET_ARG(pc, t->u.parenIndex);
1523
+ pc += ARG_LEN;
1524
+ break;
1525
+ case REOP_ASSERT:
1526
+ JS_ASSERT(emitStateSP);
1527
+ emitStateSP->nextTermFixup = pc;
1528
+ pc += OFFSET_LEN;
1529
+ emitStateSP->continueNode = t;
1530
+ emitStateSP->continueOp = REOP_ASSERTTEST;
1531
+ ++emitStateSP;
1532
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1533
+ t = (RENode *) t->kid;
1534
+ op = t->op;
1535
+ continue;
1536
+ case REOP_ASSERTTEST:
1537
+ case REOP_ASSERTNOTTEST:
1538
+ diff = pc - emitStateSP->nextTermFixup;
1539
+ CHECK_OFFSET(diff);
1540
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
1541
+ break;
1542
+ case REOP_ASSERT_NOT:
1543
+ JS_ASSERT(emitStateSP);
1544
+ emitStateSP->nextTermFixup = pc;
1545
+ pc += OFFSET_LEN;
1546
+ emitStateSP->continueNode = t;
1547
+ emitStateSP->continueOp = REOP_ASSERTNOTTEST;
1548
+ ++emitStateSP;
1549
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1550
+ t = (RENode *) t->kid;
1551
+ op = t->op;
1552
+ continue;
1553
+ case REOP_QUANT:
1554
+ JS_ASSERT(emitStateSP);
1555
+ if (t->u.range.min == 0 && t->u.range.max == (uint16)-1) {
1556
+ pc[-1] = (t->u.range.greedy) ? REOP_STAR : REOP_MINIMALSTAR;
1557
+ } else if (t->u.range.min == 0 && t->u.range.max == 1) {
1558
+ pc[-1] = (t->u.range.greedy) ? REOP_OPT : REOP_MINIMALOPT;
1559
+ } else if (t->u.range.min == 1 && t->u.range.max == (uint16) -1) {
1560
+ pc[-1] = (t->u.range.greedy) ? REOP_PLUS : REOP_MINIMALPLUS;
1561
+ } else {
1562
+ if (!t->u.range.greedy)
1563
+ pc[-1] = REOP_MINIMALQUANT;
1564
+ SET_ARG(pc, t->u.range.min);
1565
+ pc += ARG_LEN;
1566
+ SET_ARG(pc, t->u.range.max);
1567
+ pc += ARG_LEN;
1568
+ }
1569
+ emitStateSP->nextTermFixup = pc;
1570
+ pc += OFFSET_LEN;
1571
+ emitStateSP->continueNode = t;
1572
+ emitStateSP->continueOp = REOP_ENDCHILD;
1573
+ ++emitStateSP;
1574
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
1575
+ t = (RENode *) t->kid;
1576
+ op = t->op;
1577
+ continue;
1578
+ case REOP_ENDCHILD:
1579
+ diff = pc - emitStateSP->nextTermFixup;
1580
+ CHECK_OFFSET(diff);
1581
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
1582
+ break;
1583
+ case REOP_CLASS:
1584
+ if (!t->u.ucclass.sense)
1585
+ pc[-1] = REOP_NCLASS;
1586
+ SET_ARG(pc, t->u.ucclass.index);
1587
+ pc += ARG_LEN;
1588
+ charSet = &re->classList[t->u.ucclass.index];
1589
+ charSet->converted = JS_FALSE;
1590
+ charSet->length = t->u.ucclass.bmsize;
1591
+ charSet->u.src.startIndex = t->u.ucclass.startIndex;
1592
+ charSet->u.src.length = t->u.ucclass.kidlen;
1593
+ charSet->sense = t->u.ucclass.sense;
1594
+ break;
1595
+ default:
1596
+ break;
1597
+ }
1598
+ t = t->next;
1599
+ if (!t) {
1600
+ if (emitStateSP == emitStateStack)
1601
+ break;
1602
+ --emitStateSP;
1603
+ t = emitStateSP->continueNode;
1604
+ op = emitStateSP->continueOp;
1605
+ }
1606
+ else
1607
+ op = t->op;
1608
+ }
1609
+ if (emitStateStack)
1610
+ JS_free(state->context, emitStateStack);
1611
+ return pc;
1612
+ }
1613
+
1614
+
1615
+ JSRegExp *
1616
+ js_NewRegExp(JSContext *cx, JSTokenStream *ts,
1617
+ JSString *str, uintN flags, JSBool flat)
1618
+ {
1619
+ JSRegExp *re;
1620
+ void *mark;
1621
+ CompilerState state;
1622
+ size_t resize;
1623
+ jsbytecode *endPC;
1624
+ uintN i;
1625
+ size_t len;
1626
+
1627
+ re = NULL;
1628
+ mark = JS_ARENA_MARK(&cx->tempPool);
1629
+
1630
+ state.context = cx;
1631
+ state.tokenStream = ts;
1632
+ state.cpbegin = state.cp = JSSTRING_CHARS(str);
1633
+ state.cpend = state.cp + JSSTRING_LENGTH(str);
1634
+ state.flags = flags;
1635
+ state.parenCount = 0;
1636
+ state.classCount = 0;
1637
+ state.progLength = 0;
1638
+ state.treeDepth = 0;
1639
+ for (i = 0; i < CLASS_CACHE_SIZE; i++)
1640
+ state.classCache[i].start = NULL;
1641
+
1642
+ len = JSSTRING_LENGTH(str);
1643
+
1644
+ if (len != 0 && flat) {
1645
+ state.result = NewRENode(&state, REOP_FLAT);
1646
+ state.result->u.flat.chr = *state.cpbegin;
1647
+ state.result->u.flat.length = JSSTRING_LENGTH(str);
1648
+ state.result->kid = (void *) state.cpbegin;
1649
+ state.progLength += 5;
1650
+ } else {
1651
+ if (!ParseRegExp(&state))
1652
+ goto out;
1653
+ }
1654
+ resize = sizeof *re + state.progLength + 1;
1655
+ re = (JSRegExp *) JS_malloc(cx, JS_ROUNDUP(resize, sizeof(jsword)));
1656
+ if (!re)
1657
+ goto out;
1658
+
1659
+ re->nrefs = 1;
1660
+ re->classCount = state.classCount;
1661
+ if (re->classCount) {
1662
+ re->classList = (RECharSet *)
1663
+ JS_malloc(cx, re->classCount * sizeof(RECharSet));
1664
+ if (!re->classList) {
1665
+ js_DestroyRegExp(cx, re);
1666
+ re = NULL;
1667
+ goto out;
1668
+ }
1669
+ } else {
1670
+ re->classList = NULL;
1671
+ }
1672
+ endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result);
1673
+ if (!endPC) {
1674
+ js_DestroyRegExp(cx, re);
1675
+ re = NULL;
1676
+ goto out;
1677
+ }
1678
+ *endPC++ = REOP_END;
1679
+ JS_ASSERT(endPC <= (re->program + (state.progLength + 1)));
1680
+
1681
+ re->flags = flags;
1682
+ re->cloneIndex = 0;
1683
+ re->parenCount = state.parenCount;
1684
+ re->source = str;
1685
+
1686
+ out:
1687
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
1688
+ return re;
1689
+ }
1690
+
1691
+ JSRegExp *
1692
+ js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
1693
+ JSString *str, JSString *opt, JSBool flat)
1694
+ {
1695
+ uintN flags;
1696
+ jschar *s;
1697
+ size_t i, n;
1698
+ char charBuf[2];
1699
+
1700
+ flags = 0;
1701
+ if (opt) {
1702
+ s = JSSTRING_CHARS(opt);
1703
+ for (i = 0, n = JSSTRING_LENGTH(opt); i < n; i++) {
1704
+ switch (s[i]) {
1705
+ case 'g':
1706
+ flags |= JSREG_GLOB;
1707
+ break;
1708
+ case 'i':
1709
+ flags |= JSREG_FOLD;
1710
+ break;
1711
+ case 'm':
1712
+ flags |= JSREG_MULTILINE;
1713
+ break;
1714
+ default:
1715
+ charBuf[0] = (char)s[i];
1716
+ charBuf[1] = '\0';
1717
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
1718
+ JSMSG_BAD_FLAG, charBuf);
1719
+ return NULL;
1720
+ }
1721
+ }
1722
+ }
1723
+ return js_NewRegExp(cx, ts, str, flags, flat);
1724
+ }
1725
+
1726
+
1727
+ #define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs)
1728
+ #define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re)
1729
+
1730
+ /*
1731
+ * Save the current state of the match - the position in the input
1732
+ * text as well as the position in the bytecode. The state of any
1733
+ * parent expressions is also saved (preceding state).
1734
+ * Contents of parenCount parentheses from parenIndex are also saved.
1735
+ */
1736
+ static REBackTrackData *
1737
+ PushBackTrackState(REGlobalData *gData, REOp op,
1738
+ jsbytecode *target, REMatchState *x, const jschar *cp,
1739
+ uintN parenIndex, intN parenCount)
1740
+ {
1741
+ intN i;
1742
+ REBackTrackData *result =
1743
+ (REBackTrackData *) ((char *)gData->backTrackSP + gData->cursz);
1744
+
1745
+ size_t sz = sizeof(REBackTrackData) +
1746
+ gData->stateStackTop * sizeof(REProgState) +
1747
+ parenCount * sizeof(RECapture);
1748
+
1749
+ ptrdiff_t btsize = gData->backTrackStackSize;
1750
+ ptrdiff_t btincr = ((char *)result + sz) -
1751
+ ((char *)gData->backTrackStack + btsize);
1752
+
1753
+ if (btincr > 0) {
1754
+ ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack;
1755
+
1756
+ btincr = JS_ROUNDUP(btincr, btsize);
1757
+ JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *,
1758
+ &gData->pool, btsize, btincr);
1759
+ if (!gData->backTrackStack)
1760
+ return NULL;
1761
+ gData->backTrackStackSize = btsize + btincr;
1762
+ result = (REBackTrackData *) ((char *)gData->backTrackStack + offset);
1763
+ }
1764
+ gData->backTrackSP = result;
1765
+ result->sz = gData->cursz;
1766
+ gData->cursz = sz;
1767
+
1768
+ result->backtrack_op = op;
1769
+ result->backtrack_pc = target;
1770
+ result->cp = cp;
1771
+ result->parenCount = parenCount;
1772
+
1773
+ result->saveStateStackTop = gData->stateStackTop;
1774
+ JS_ASSERT(gData->stateStackTop);
1775
+ memcpy(result + 1, gData->stateStack,
1776
+ sizeof(REProgState) * result->saveStateStackTop);
1777
+
1778
+ /* FIXME: parenCount should be uintN */
1779
+ JS_ASSERT(parenCount >= 0);
1780
+ if (parenCount > 0) {
1781
+ result->parenIndex = parenIndex;
1782
+ memcpy((char *)(result + 1) +
1783
+ sizeof(REProgState) * result->saveStateStackTop,
1784
+ &x->parens[parenIndex],
1785
+ sizeof(RECapture) * parenCount);
1786
+ for (i = 0; i < parenCount; i++)
1787
+ x->parens[parenIndex + i].index = -1;
1788
+ }
1789
+
1790
+ return result;
1791
+ }
1792
+
1793
+
1794
+ /*
1795
+ * Consecutive literal characters.
1796
+ */
1797
+ #if 0
1798
+ static REMatchState *
1799
+ FlatNMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
1800
+ intN length)
1801
+ {
1802
+ intN i;
1803
+ if (x->cp + length > gData->cpend)
1804
+ return NULL;
1805
+ for (i = 0; i < length; i++) {
1806
+ if (matchChars[i] != x->cp[i])
1807
+ return NULL;
1808
+ }
1809
+ x->cp += length;
1810
+ return x;
1811
+ }
1812
+ #endif
1813
+
1814
+ static REMatchState *
1815
+ FlatNIMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
1816
+ intN length)
1817
+ {
1818
+ intN i;
1819
+ if (x->cp + length > gData->cpend)
1820
+ return NULL;
1821
+ for (i = 0; i < length; i++) {
1822
+ if (upcase(matchChars[i]) != upcase(x->cp[i]))
1823
+ return NULL;
1824
+ }
1825
+ x->cp += length;
1826
+ return x;
1827
+ }
1828
+
1829
+ /*
1830
+ * 1. Evaluate DecimalEscape to obtain an EscapeValue E.
1831
+ * 2. If E is not a character then go to step 6.
1832
+ * 3. Let ch be E's character.
1833
+ * 4. Let A be a one-element RECharSet containing the character ch.
1834
+ * 5. Call CharacterSetMatcher(A, false) and return its Matcher result.
1835
+ * 6. E must be an integer. Let n be that integer.
1836
+ * 7. If n=0 or n>NCapturingParens then throw a SyntaxError exception.
1837
+ * 8. Return an internal Matcher closure that takes two arguments, a State x
1838
+ * and a Continuation c, and performs the following:
1839
+ * 1. Let cap be x's captures internal array.
1840
+ * 2. Let s be cap[n].
1841
+ * 3. If s is undefined, then call c(x) and return its result.
1842
+ * 4. Let e be x's endIndex.
1843
+ * 5. Let len be s's length.
1844
+ * 6. Let f be e+len.
1845
+ * 7. If f>InputLength, return failure.
1846
+ * 8. If there exists an integer i between 0 (inclusive) and len (exclusive)
1847
+ * such that Canonicalize(s[i]) is not the same character as
1848
+ * Canonicalize(Input [e+i]), then return failure.
1849
+ * 9. Let y be the State (f, cap).
1850
+ * 10. Call c(y) and return its result.
1851
+ */
1852
+ static REMatchState *
1853
+ BackrefMatcher(REGlobalData *gData, REMatchState *x, uintN parenIndex)
1854
+ {
1855
+ uintN len;
1856
+ uintN i;
1857
+ const jschar *parenContent;
1858
+ RECapture *s = &x->parens[parenIndex];
1859
+ if (s->index == -1)
1860
+ return x;
1861
+
1862
+ len = s->length;
1863
+ if (x->cp + len > gData->cpend)
1864
+ return NULL;
1865
+
1866
+ parenContent = &gData->cpbegin[s->index];
1867
+ if (gData->regexp->flags & JSREG_FOLD) {
1868
+ for (i = 0; i < len; i++) {
1869
+ if (upcase(parenContent[i]) != upcase(x->cp[i]))
1870
+ return NULL;
1871
+ }
1872
+ } else {
1873
+ for (i = 0; i < len; i++) {
1874
+ if (parenContent[i] != x->cp[i])
1875
+ return NULL;
1876
+ }
1877
+ }
1878
+ x->cp += len;
1879
+ return x;
1880
+ }
1881
+
1882
+
1883
+ /* Add a single character to the RECharSet */
1884
+ static void
1885
+ AddCharacterToCharSet(RECharSet *cs, jschar c)
1886
+ {
1887
+ uintN byteIndex = (uintN)(c >> 3);
1888
+ JS_ASSERT(c <= cs->length);
1889
+ cs->u.bits[byteIndex] |= 1 << (c & 0x7);
1890
+ }
1891
+
1892
+
1893
+ /* Add a character range, c1 to c2 (inclusive) to the RECharSet */
1894
+ static void
1895
+ AddCharacterRangeToCharSet(RECharSet *cs, jschar c1, jschar c2)
1896
+ {
1897
+ uintN i;
1898
+
1899
+ uintN byteIndex1 = (uintN)(c1 >> 3);
1900
+ uintN byteIndex2 = (uintN)(c2 >> 3);
1901
+
1902
+ JS_ASSERT((c2 <= cs->length) && (c1 <= c2));
1903
+
1904
+ c1 &= 0x7;
1905
+ c2 &= 0x7;
1906
+
1907
+ if (byteIndex1 == byteIndex2) {
1908
+ cs->u.bits[byteIndex1] |= ((uint8)0xFF >> (7 - (c2 - c1))) << c1;
1909
+ } else {
1910
+ cs->u.bits[byteIndex1] |= 0xFF << c1;
1911
+ for (i = byteIndex1 + 1; i < byteIndex2; i++)
1912
+ cs->u.bits[i] = 0xFF;
1913
+ cs->u.bits[byteIndex2] |= (uint8)0xFF >> (7 - c2);
1914
+ }
1915
+ }
1916
+
1917
+ /* Compile the source of the class into a RECharSet */
1918
+ static JSBool
1919
+ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
1920
+ {
1921
+ const jschar *src = JSSTRING_CHARS(gData->regexp->source) +
1922
+ charSet->u.src.startIndex;
1923
+ const jschar *end = src + charSet->u.src.length;
1924
+
1925
+ JSBool inRange = JS_FALSE;
1926
+ jschar rangeStart = 0;
1927
+ uintN byteLength, n;
1928
+ jschar c, thisCh;
1929
+ intN nDigits, i;
1930
+
1931
+ JS_ASSERT(!charSet->converted);
1932
+ charSet->converted = JS_TRUE;
1933
+
1934
+ byteLength = (charSet->length >> 3) + 1;
1935
+ charSet->u.bits = (uint8 *)JS_malloc(gData->cx, byteLength);
1936
+ if (!charSet->u.bits)
1937
+ return JS_FALSE;
1938
+ memset(charSet->u.bits, 0, byteLength);
1939
+
1940
+ if (src == end)
1941
+ return JS_TRUE;
1942
+
1943
+ if (*src == '^') {
1944
+ JS_ASSERT(charSet->sense == JS_FALSE);
1945
+ ++src;
1946
+ }
1947
+ else
1948
+ JS_ASSERT(charSet->sense == JS_TRUE);
1949
+
1950
+
1951
+ while (src != end) {
1952
+ switch (*src) {
1953
+ case '\\':
1954
+ ++src;
1955
+ c = *src++;
1956
+ switch (c) {
1957
+ case 'b':
1958
+ thisCh = 0x8;
1959
+ break;
1960
+ case 'f':
1961
+ thisCh = 0xC;
1962
+ break;
1963
+ case 'n':
1964
+ thisCh = 0xA;
1965
+ break;
1966
+ case 'r':
1967
+ thisCh = 0xD;
1968
+ break;
1969
+ case 't':
1970
+ thisCh = 0x9;
1971
+ break;
1972
+ case 'v':
1973
+ thisCh = 0xB;
1974
+ break;
1975
+ case 'c':
1976
+ if (src + 1 < end && JS_ISWORD(src[1])) {
1977
+ thisCh = (jschar)(*src++ & 0x1F);
1978
+ } else {
1979
+ --src;
1980
+ thisCh = '\\';
1981
+ }
1982
+ break;
1983
+ case 'x':
1984
+ nDigits = 2;
1985
+ goto lexHex;
1986
+ case 'u':
1987
+ nDigits = 4;
1988
+ lexHex:
1989
+ n = 0;
1990
+ for (i = 0; (i < nDigits) && (src < end); i++) {
1991
+ uintN digit;
1992
+ c = *src++;
1993
+ if (!isASCIIHexDigit(c, &digit)) {
1994
+ /*
1995
+ * Back off to accepting the original '\'
1996
+ * as a literal
1997
+ */
1998
+ src -= i + 1;
1999
+ n = '\\';
2000
+ break;
2001
+ }
2002
+ n = (n << 4) | digit;
2003
+ }
2004
+ thisCh = (jschar)n;
2005
+ break;
2006
+ case '0':
2007
+ case '1':
2008
+ case '2':
2009
+ case '3':
2010
+ case '4':
2011
+ case '5':
2012
+ case '6':
2013
+ case '7':
2014
+ /*
2015
+ * This is a non-ECMA extension - decimal escapes (in this
2016
+ * case, octal!) are supposed to be an error inside class
2017
+ * ranges, but supported here for backwards compatibility.
2018
+ *
2019
+ */
2020
+ n = JS7_UNDEC(c);
2021
+ c = *src;
2022
+ if ('0' <= c && c <= '7') {
2023
+ src++;
2024
+ n = 8 * n + JS7_UNDEC(c);
2025
+ c = *src;
2026
+ if ('0' <= c && c <= '7') {
2027
+ src++;
2028
+ i = 8 * n + JS7_UNDEC(c);
2029
+ if (i <= 0377)
2030
+ n = i;
2031
+ else
2032
+ src--;
2033
+ }
2034
+ }
2035
+ thisCh = (jschar)n;
2036
+ break;
2037
+
2038
+ case 'd':
2039
+ AddCharacterRangeToCharSet(charSet, '0', '9');
2040
+ continue; /* don't need range processing */
2041
+ case 'D':
2042
+ AddCharacterRangeToCharSet(charSet, 0, '0' - 1);
2043
+ AddCharacterRangeToCharSet(charSet,
2044
+ (jschar)('9' + 1),
2045
+ (jschar)charSet->length);
2046
+ continue;
2047
+ case 's':
2048
+ for (i = (intN)charSet->length; i >= 0; i--)
2049
+ if (JS_ISSPACE(i))
2050
+ AddCharacterToCharSet(charSet, (jschar)i);
2051
+ continue;
2052
+ case 'S':
2053
+ for (i = (intN)charSet->length; i >= 0; i--)
2054
+ if (!JS_ISSPACE(i))
2055
+ AddCharacterToCharSet(charSet, (jschar)i);
2056
+ continue;
2057
+ case 'w':
2058
+ for (i = (intN)charSet->length; i >= 0; i--)
2059
+ if (JS_ISWORD(i))
2060
+ AddCharacterToCharSet(charSet, (jschar)i);
2061
+ continue;
2062
+ case 'W':
2063
+ for (i = (intN)charSet->length; i >= 0; i--)
2064
+ if (!JS_ISWORD(i))
2065
+ AddCharacterToCharSet(charSet, (jschar)i);
2066
+ continue;
2067
+ default:
2068
+ thisCh = c;
2069
+ break;
2070
+
2071
+ }
2072
+ break;
2073
+
2074
+ default:
2075
+ thisCh = *src++;
2076
+ break;
2077
+
2078
+ }
2079
+ if (inRange) {
2080
+ if (gData->regexp->flags & JSREG_FOLD) {
2081
+ AddCharacterRangeToCharSet(charSet, upcase(rangeStart),
2082
+ upcase(thisCh));
2083
+ AddCharacterRangeToCharSet(charSet, downcase(rangeStart),
2084
+ downcase(thisCh));
2085
+ } else {
2086
+ AddCharacterRangeToCharSet(charSet, rangeStart, thisCh);
2087
+ }
2088
+ inRange = JS_FALSE;
2089
+ } else {
2090
+ if (gData->regexp->flags & JSREG_FOLD) {
2091
+ AddCharacterToCharSet(charSet, upcase(thisCh));
2092
+ AddCharacterToCharSet(charSet, downcase(thisCh));
2093
+ } else {
2094
+ AddCharacterToCharSet(charSet, thisCh);
2095
+ }
2096
+ if (src < end - 1) {
2097
+ if (*src == '-') {
2098
+ ++src;
2099
+ inRange = JS_TRUE;
2100
+ rangeStart = thisCh;
2101
+ }
2102
+ }
2103
+ }
2104
+ }
2105
+ return JS_TRUE;
2106
+ }
2107
+
2108
+ void
2109
+ js_DestroyRegExp(JSContext *cx, JSRegExp *re)
2110
+ {
2111
+ if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) {
2112
+ if (re->classList) {
2113
+ uintN i;
2114
+ for (i = 0; i < re->classCount; i++) {
2115
+ if (re->classList[i].converted)
2116
+ JS_free(cx, re->classList[i].u.bits);
2117
+ re->classList[i].u.bits = NULL;
2118
+ }
2119
+ JS_free(cx, re->classList);
2120
+ }
2121
+ JS_free(cx, re);
2122
+ }
2123
+ }
2124
+
2125
+ static JSBool
2126
+ ReallocStateStack(REGlobalData *gData)
2127
+ {
2128
+ uint16 limit = gData->stateStackLimit;
2129
+ size_t sz = sizeof(REProgState) * limit;
2130
+
2131
+ JS_ARENA_GROW_CAST(gData->stateStack, REProgState *, &gData->pool, sz, sz);
2132
+ if (!gData->stateStack) {
2133
+ gData->ok = JS_FALSE;
2134
+ return JS_FALSE;
2135
+ }
2136
+ gData->stateStackLimit = limit + limit;
2137
+ return JS_TRUE;
2138
+ }
2139
+
2140
+ #define PUSH_STATE_STACK(data) \
2141
+ JS_BEGIN_MACRO \
2142
+ ++(data)->stateStackTop; \
2143
+ if ((data)->stateStackTop == (data)->stateStackLimit && \
2144
+ !ReallocStateStack((data))) { \
2145
+ return NULL; \
2146
+ } \
2147
+ JS_END_MACRO
2148
+
2149
+ /*
2150
+ * Apply the current op against the given input to see if it's going to match
2151
+ * or fail. Return false if we don't get a match, true if we do and update the
2152
+ * state of the input and pc if the update flag is true.
2153
+ */
2154
+ static REMatchState *
2155
+ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
2156
+ jsbytecode **startpc, JSBool update)
2157
+ {
2158
+ REMatchState *result = NULL;
2159
+ jschar matchCh;
2160
+ uintN parenIndex;
2161
+ intN offset, length, index;
2162
+ jsbytecode *pc = *startpc; /* pc has already been incremented past op */
2163
+ jschar *source;
2164
+ const jschar *startcp = x->cp;
2165
+ jschar ch;
2166
+ RECharSet *charSet;
2167
+
2168
+ switch (op) {
2169
+ case REOP_BOL:
2170
+ if (x->cp != gData->cpbegin) {
2171
+ if (!gData->cx->regExpStatics.multiline &&
2172
+ !(gData->regexp->flags & JSREG_MULTILINE)) {
2173
+ break;
2174
+ }
2175
+ if (!RE_IS_LINE_TERM(x->cp[-1]))
2176
+ break;
2177
+ }
2178
+ result = x;
2179
+ break;
2180
+ case REOP_EOL:
2181
+ if (x->cp != gData->cpend) {
2182
+ if (!gData->cx->regExpStatics.multiline &&
2183
+ !(gData->regexp->flags & JSREG_MULTILINE)) {
2184
+ break;
2185
+ }
2186
+ if (!RE_IS_LINE_TERM(*x->cp))
2187
+ break;
2188
+ }
2189
+ result = x;
2190
+ break;
2191
+ case REOP_WBDRY:
2192
+ if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1])) ^
2193
+ !(x->cp != gData->cpend && JS_ISWORD(*x->cp))) {
2194
+ result = x;
2195
+ }
2196
+ break;
2197
+ case REOP_WNONBDRY:
2198
+ if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1])) ^
2199
+ (x->cp != gData->cpend && JS_ISWORD(*x->cp))) {
2200
+ result = x;
2201
+ }
2202
+ break;
2203
+ case REOP_DOT:
2204
+ if (x->cp != gData->cpend && !RE_IS_LINE_TERM(*x->cp)) {
2205
+ result = x;
2206
+ result->cp++;
2207
+ }
2208
+ break;
2209
+ case REOP_DIGIT:
2210
+ if (x->cp != gData->cpend && JS_ISDIGIT(*x->cp)) {
2211
+ result = x;
2212
+ result->cp++;
2213
+ }
2214
+ break;
2215
+ case REOP_NONDIGIT:
2216
+ if (x->cp != gData->cpend && !JS_ISDIGIT(*x->cp)) {
2217
+ result = x;
2218
+ result->cp++;
2219
+ }
2220
+ break;
2221
+ case REOP_ALNUM:
2222
+ if (x->cp != gData->cpend && JS_ISWORD(*x->cp)) {
2223
+ result = x;
2224
+ result->cp++;
2225
+ }
2226
+ break;
2227
+ case REOP_NONALNUM:
2228
+ if (x->cp != gData->cpend && !JS_ISWORD(*x->cp)) {
2229
+ result = x;
2230
+ result->cp++;
2231
+ }
2232
+ break;
2233
+ case REOP_SPACE:
2234
+ if (x->cp != gData->cpend && JS_ISSPACE(*x->cp)) {
2235
+ result = x;
2236
+ result->cp++;
2237
+ }
2238
+ break;
2239
+ case REOP_NONSPACE:
2240
+ if (x->cp != gData->cpend && !JS_ISSPACE(*x->cp)) {
2241
+ result = x;
2242
+ result->cp++;
2243
+ }
2244
+ break;
2245
+ case REOP_BACKREF:
2246
+ parenIndex = GET_ARG(pc);
2247
+ pc += ARG_LEN;
2248
+ result = BackrefMatcher(gData, x, parenIndex);
2249
+ break;
2250
+ case REOP_FLAT:
2251
+ offset = GET_ARG(pc);
2252
+ pc += ARG_LEN;
2253
+ length = GET_ARG(pc);
2254
+ pc += ARG_LEN;
2255
+ source = JSSTRING_CHARS(gData->regexp->source) + offset;
2256
+ if (x->cp + length <= gData->cpend) {
2257
+ for (index = 0; index < length; index++) {
2258
+ if (source[index] != x->cp[index])
2259
+ return NULL;
2260
+ }
2261
+ x->cp += length;
2262
+ result = x;
2263
+ }
2264
+ break;
2265
+ case REOP_FLAT1:
2266
+ matchCh = *pc++;
2267
+ if (x->cp != gData->cpend && *x->cp == matchCh) {
2268
+ result = x;
2269
+ result->cp++;
2270
+ }
2271
+ break;
2272
+ case REOP_FLATi:
2273
+ offset = GET_ARG(pc);
2274
+ pc += ARG_LEN;
2275
+ length = GET_ARG(pc);
2276
+ pc += ARG_LEN;
2277
+ source = JSSTRING_CHARS(gData->regexp->source);
2278
+ result = FlatNIMatcher(gData, x, source + offset, length);
2279
+ break;
2280
+ case REOP_FLAT1i:
2281
+ matchCh = *pc++;
2282
+ if (x->cp != gData->cpend && upcase(*x->cp) == upcase(matchCh)) {
2283
+ result = x;
2284
+ result->cp++;
2285
+ }
2286
+ break;
2287
+ case REOP_UCFLAT1:
2288
+ matchCh = GET_ARG(pc);
2289
+ pc += ARG_LEN;
2290
+ if (x->cp != gData->cpend && *x->cp == matchCh) {
2291
+ result = x;
2292
+ result->cp++;
2293
+ }
2294
+ break;
2295
+ case REOP_UCFLAT1i:
2296
+ matchCh = GET_ARG(pc);
2297
+ pc += ARG_LEN;
2298
+ if (x->cp != gData->cpend && upcase(*x->cp) == upcase(matchCh)) {
2299
+ result = x;
2300
+ result->cp++;
2301
+ }
2302
+ break;
2303
+ case REOP_CLASS:
2304
+ index = GET_ARG(pc);
2305
+ pc += ARG_LEN;
2306
+ if (x->cp != gData->cpend) {
2307
+ charSet = &gData->regexp->classList[index];
2308
+ JS_ASSERT(charSet->converted);
2309
+ ch = *x->cp;
2310
+ index = ch >> 3;
2311
+ if (charSet->length != 0 &&
2312
+ ch <= charSet->length &&
2313
+ (charSet->u.bits[index] & (1 << (ch & 0x7)))) {
2314
+ result = x;
2315
+ result->cp++;
2316
+ }
2317
+ }
2318
+ break;
2319
+ case REOP_NCLASS:
2320
+ index = GET_ARG(pc);
2321
+ pc += ARG_LEN;
2322
+ if (x->cp != gData->cpend) {
2323
+ charSet = &gData->regexp->classList[index];
2324
+ JS_ASSERT(charSet->converted);
2325
+ ch = *x->cp;
2326
+ index = ch >> 3;
2327
+ if (charSet->length == 0 ||
2328
+ ch > charSet->length ||
2329
+ !(charSet->u.bits[index] & (1 << (ch & 0x7)))) {
2330
+ result = x;
2331
+ result->cp++;
2332
+ }
2333
+ }
2334
+ break;
2335
+ default:
2336
+ JS_ASSERT(JS_FALSE);
2337
+ }
2338
+ if (result) {
2339
+ if (update)
2340
+ *startpc = pc;
2341
+ else
2342
+ x->cp = startcp;
2343
+ return result;
2344
+ }
2345
+ x->cp = startcp;
2346
+ return NULL;
2347
+ }
2348
+
2349
+ static REMatchState *
2350
+ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
2351
+ {
2352
+ REMatchState *result = NULL;
2353
+ REBackTrackData *backTrackData;
2354
+ intN offset;
2355
+ jsbytecode *nextpc;
2356
+ REOp nextop;
2357
+ RECapture *cap;
2358
+ REProgState *curState;
2359
+ const jschar *startcp;
2360
+ uintN parenIndex, k;
2361
+ uintN parenSoFar = 0;
2362
+
2363
+ jschar matchCh1, matchCh2;
2364
+ RECharSet *charSet;
2365
+
2366
+ JSBool anchor;
2367
+ jsbytecode *pc = gData->regexp->program;
2368
+ REOp op = (REOp) *pc++;
2369
+
2370
+ /*
2371
+ * If the first node is a simple match, step the index into the string
2372
+ * until that match is made, or fail if it can't be found at all.
2373
+ */
2374
+ if (REOP_IS_SIMPLE(op)) {
2375
+ anchor = JS_FALSE;
2376
+ while (x->cp <= gData->cpend) {
2377
+ nextpc = pc; /* reset back to start each time */
2378
+ result = SimpleMatch(gData, x, op, &nextpc, JS_TRUE);
2379
+ if (result) {
2380
+ anchor = JS_TRUE;
2381
+ x = result;
2382
+ pc = nextpc; /* accept skip to next opcode */
2383
+ op = (REOp) *pc++;
2384
+ break;
2385
+ }
2386
+ gData->skipped++;
2387
+ x->cp++;
2388
+ }
2389
+ if (!anchor)
2390
+ return NULL;
2391
+ }
2392
+
2393
+ while (JS_TRUE) {
2394
+ if (REOP_IS_SIMPLE(op)) {
2395
+ result = SimpleMatch(gData, x, op, &pc, JS_TRUE);
2396
+ } else {
2397
+ curState = &gData->stateStack[gData->stateStackTop];
2398
+ switch (op) {
2399
+ case REOP_EMPTY:
2400
+ result = x;
2401
+ break;
2402
+
2403
+ case REOP_ALTPREREQ2:
2404
+ nextpc = pc + GET_OFFSET(pc); /* start of next op */
2405
+ pc += ARG_LEN;
2406
+ matchCh2 = GET_ARG(pc);
2407
+ pc += ARG_LEN;
2408
+ k = GET_ARG(pc);
2409
+ pc += ARG_LEN;
2410
+
2411
+ if (x->cp != gData->cpend) {
2412
+ if (*x->cp == matchCh2)
2413
+ goto doAlt;
2414
+
2415
+ charSet = &gData->regexp->classList[k];
2416
+ if (!charSet->converted)
2417
+ if (!ProcessCharSet(gData, charSet))
2418
+ return NULL;
2419
+ matchCh1 = *x->cp;
2420
+ k = matchCh1 >> 3;
2421
+ if ((charSet->length == 0 ||
2422
+ matchCh1 > charSet->length ||
2423
+ !(charSet->u.bits[k] & (1 << (matchCh1 & 0x7)))) ^
2424
+ charSet->sense) {
2425
+ goto doAlt;
2426
+ }
2427
+ }
2428
+ result = NULL;
2429
+ break;
2430
+
2431
+ case REOP_ALTPREREQ:
2432
+ nextpc = pc + GET_OFFSET(pc); /* start of next op */
2433
+ pc += ARG_LEN;
2434
+ matchCh1 = GET_ARG(pc);
2435
+ pc += ARG_LEN;
2436
+ matchCh2 = GET_ARG(pc);
2437
+ pc += ARG_LEN;
2438
+ if (x->cp == gData->cpend ||
2439
+ (*x->cp != matchCh1 && *x->cp != matchCh2)) {
2440
+ result = NULL;
2441
+ break;
2442
+ }
2443
+ /* else false thru... */
2444
+
2445
+ case REOP_ALT:
2446
+ doAlt:
2447
+ nextpc = pc + GET_OFFSET(pc); /* start of next alternate */
2448
+ pc += ARG_LEN; /* start of this alternate */
2449
+ curState->parenSoFar = parenSoFar;
2450
+ PUSH_STATE_STACK(gData);
2451
+ op = (REOp) *pc++;
2452
+ startcp = x->cp;
2453
+ if (REOP_IS_SIMPLE(op)) {
2454
+ if (!SimpleMatch(gData, x, op, &pc, JS_TRUE)) {
2455
+ op = (REOp) *nextpc++;
2456
+ pc = nextpc;
2457
+ continue;
2458
+ }
2459
+ result = x;
2460
+ op = (REOp) *pc++;
2461
+ }
2462
+ nextop = (REOp) *nextpc++;
2463
+ if (!PushBackTrackState(gData, nextop, nextpc, x, startcp, 0, 0))
2464
+ return NULL;
2465
+ continue;
2466
+
2467
+ /*
2468
+ * Occurs at (succesful) end of REOP_ALT,
2469
+ */
2470
+ case REOP_JUMP:
2471
+ --gData->stateStackTop;
2472
+ offset = GET_OFFSET(pc);
2473
+ pc += offset;
2474
+ op = (REOp) *pc++;
2475
+ continue;
2476
+
2477
+ /*
2478
+ * Occurs at last (succesful) end of REOP_ALT,
2479
+ */
2480
+ case REOP_ENDALT:
2481
+ --gData->stateStackTop;
2482
+ op = (REOp) *pc++;
2483
+ continue;
2484
+
2485
+ case REOP_LPAREN:
2486
+ parenIndex = GET_ARG(pc);
2487
+ if (parenIndex + 1 > parenSoFar)
2488
+ parenSoFar = parenIndex + 1;
2489
+ pc += ARG_LEN;
2490
+ x->parens[parenIndex].index = x->cp - gData->cpbegin;
2491
+ x->parens[parenIndex].length = 0;
2492
+ op = (REOp) *pc++;
2493
+ continue;
2494
+ case REOP_RPAREN:
2495
+ parenIndex = GET_ARG(pc);
2496
+ pc += ARG_LEN;
2497
+ cap = &x->parens[parenIndex];
2498
+ cap->length = x->cp - (gData->cpbegin + cap->index);
2499
+ op = (REOp) *pc++;
2500
+ continue;
2501
+
2502
+ case REOP_ASSERT:
2503
+ nextpc = pc + GET_OFFSET(pc); /* start of term after ASSERT */
2504
+ pc += ARG_LEN; /* start of ASSERT child */
2505
+ op = (REOp) *pc++;
2506
+ if (REOP_IS_SIMPLE(op) &&
2507
+ !SimpleMatch(gData, x, op, &pc, JS_FALSE)) {
2508
+ result = NULL;
2509
+ break;
2510
+ }
2511
+ curState->u.assertion.top =
2512
+ (char *)gData->backTrackSP - (char *)gData->backTrackStack;
2513
+ curState->u.assertion.sz = gData->cursz;
2514
+ curState->index = x->cp - gData->cpbegin;
2515
+ curState->parenSoFar = parenSoFar;
2516
+ PUSH_STATE_STACK(gData);
2517
+ if (!PushBackTrackState(gData, REOP_ASSERTTEST,
2518
+ nextpc, x, x->cp, 0, 0)) {
2519
+ return NULL;
2520
+ }
2521
+ continue;
2522
+ case REOP_ASSERT_NOT:
2523
+ nextpc = pc + GET_OFFSET(pc);
2524
+ pc += ARG_LEN;
2525
+ op = (REOp) *pc++;
2526
+ if (REOP_IS_SIMPLE(op) /* Note - fail to fail! */ &&
2527
+ SimpleMatch(gData, x, op, &pc, JS_FALSE) &&
2528
+ pc == nextpc) {
2529
+ result = NULL;
2530
+ break;
2531
+ }
2532
+ curState->u.assertion.top
2533
+ = (char *)gData->backTrackSP -
2534
+ (char *)gData->backTrackStack;
2535
+ curState->u.assertion.sz = gData->cursz;
2536
+ curState->index = x->cp - gData->cpbegin;
2537
+ curState->parenSoFar = parenSoFar;
2538
+ PUSH_STATE_STACK(gData);
2539
+ if (!PushBackTrackState(gData, REOP_ASSERTNOTTEST,
2540
+ nextpc, x, x->cp, 0, 0))
2541
+ return NULL;
2542
+ continue;
2543
+ case REOP_ASSERTTEST:
2544
+ --gData->stateStackTop;
2545
+ --curState;
2546
+ x->cp = gData->cpbegin + curState->index;
2547
+ gData->backTrackSP =
2548
+ (REBackTrackData *) ((char *)gData->backTrackStack +
2549
+ curState->u.assertion.top);
2550
+ gData->cursz = curState->u.assertion.sz;
2551
+ if (result)
2552
+ result = x;
2553
+ break;
2554
+ case REOP_ASSERTNOTTEST:
2555
+ --gData->stateStackTop;
2556
+ --curState;
2557
+ x->cp = gData->cpbegin + curState->index;
2558
+ gData->backTrackSP =
2559
+ (REBackTrackData *) ((char *)gData->backTrackStack +
2560
+ curState->u.assertion.top);
2561
+ gData->cursz = curState->u.assertion.sz;
2562
+ result = (!result) ? x : NULL;
2563
+ break;
2564
+
2565
+ case REOP_END:
2566
+ if (x)
2567
+ return x;
2568
+ break;
2569
+
2570
+ case REOP_STAR:
2571
+ curState->u.quantifier.min = 0;
2572
+ curState->u.quantifier.max = (uint16)-1;
2573
+ goto quantcommon;
2574
+ case REOP_PLUS:
2575
+ curState->u.quantifier.min = 1;
2576
+ curState->u.quantifier.max = (uint16)-1;
2577
+ goto quantcommon;
2578
+ case REOP_OPT:
2579
+ curState->u.quantifier.min = 0;
2580
+ curState->u.quantifier.max = 1;
2581
+ goto quantcommon;
2582
+ case REOP_QUANT:
2583
+ curState->u.quantifier.min = GET_ARG(pc);
2584
+ pc += ARG_LEN;
2585
+ curState->u.quantifier.max = GET_ARG(pc);
2586
+ pc += ARG_LEN;
2587
+ quantcommon:
2588
+ if (curState->u.quantifier.max == 0) {
2589
+ pc = pc + GET_OFFSET(pc);
2590
+ op = (REOp) *pc++;
2591
+ result = x;
2592
+ continue;
2593
+ }
2594
+ /* Step over <next> */
2595
+ nextpc = pc + ARG_LEN;
2596
+ op = (REOp) *nextpc++;
2597
+ startcp = x->cp;
2598
+ if (REOP_IS_SIMPLE(op)) {
2599
+ if (!SimpleMatch(gData, x, op, &nextpc, JS_TRUE)) {
2600
+ if (curState->u.quantifier.min == 0)
2601
+ result = x;
2602
+ else
2603
+ result = NULL;
2604
+ pc = pc + GET_OFFSET(pc);
2605
+ break;
2606
+ }
2607
+ op = (REOp) *nextpc++;
2608
+ result = x;
2609
+ }
2610
+ curState->index = startcp - gData->cpbegin;
2611
+ curState->continue_op = REOP_REPEAT;
2612
+ curState->continue_pc = pc;
2613
+ curState->parenSoFar = parenSoFar;
2614
+ PUSH_STATE_STACK(gData);
2615
+ if (curState->u.quantifier.min == 0 &&
2616
+ !PushBackTrackState(gData, REOP_REPEAT, pc, x, startcp,
2617
+ 0, 0)) {
2618
+ return NULL;
2619
+ }
2620
+ pc = nextpc;
2621
+ continue;
2622
+
2623
+ case REOP_ENDCHILD: /* marks the end of a quantifier child */
2624
+ pc = curState[-1].continue_pc;
2625
+ op = curState[-1].continue_op;
2626
+ continue;
2627
+
2628
+ case REOP_REPEAT:
2629
+ --curState;
2630
+ do {
2631
+ --gData->stateStackTop;
2632
+ if (!result) {
2633
+ /* Failed, see if we have enough children. */
2634
+ if (curState->u.quantifier.min == 0)
2635
+ goto repeatDone;
2636
+ goto break_switch;
2637
+ }
2638
+ if (curState->u.quantifier.min == 0 &&
2639
+ x->cp == gData->cpbegin + curState->index) {
2640
+ /* matched an empty string, that'll get us nowhere */
2641
+ result = NULL;
2642
+ goto break_switch;
2643
+ }
2644
+ if (curState->u.quantifier.min != 0)
2645
+ curState->u.quantifier.min--;
2646
+ if (curState->u.quantifier.max != (uint16) -1)
2647
+ curState->u.quantifier.max--;
2648
+ if (curState->u.quantifier.max == 0)
2649
+ goto repeatDone;
2650
+ nextpc = pc + ARG_LEN;
2651
+ nextop = (REOp) *nextpc;
2652
+ startcp = x->cp;
2653
+ if (REOP_IS_SIMPLE(nextop)) {
2654
+ nextpc++;
2655
+ if (!SimpleMatch(gData, x, nextop, &nextpc, JS_TRUE)) {
2656
+ if (curState->u.quantifier.min == 0)
2657
+ goto repeatDone;
2658
+ result = NULL;
2659
+ goto break_switch;
2660
+ }
2661
+ result = x;
2662
+ }
2663
+ curState->index = startcp - gData->cpbegin;
2664
+ PUSH_STATE_STACK(gData);
2665
+ if (curState->u.quantifier.min == 0 &&
2666
+ !PushBackTrackState(gData, REOP_REPEAT,
2667
+ pc, x, startcp,
2668
+ curState->parenSoFar,
2669
+ parenSoFar -
2670
+ curState->parenSoFar)) {
2671
+ return NULL;
2672
+ }
2673
+ } while (*nextpc == REOP_ENDCHILD);
2674
+ pc = nextpc;
2675
+ op = (REOp) *pc++;
2676
+ parenSoFar = curState->parenSoFar;
2677
+ continue;
2678
+
2679
+ repeatDone:
2680
+ result = x;
2681
+ pc += GET_OFFSET(pc);
2682
+ goto break_switch;
2683
+
2684
+ case REOP_MINIMALSTAR:
2685
+ curState->u.quantifier.min = 0;
2686
+ curState->u.quantifier.max = (uint16)-1;
2687
+ goto minimalquantcommon;
2688
+ case REOP_MINIMALPLUS:
2689
+ curState->u.quantifier.min = 1;
2690
+ curState->u.quantifier.max = (uint16)-1;
2691
+ goto minimalquantcommon;
2692
+ case REOP_MINIMALOPT:
2693
+ curState->u.quantifier.min = 0;
2694
+ curState->u.quantifier.max = 1;
2695
+ goto minimalquantcommon;
2696
+ case REOP_MINIMALQUANT:
2697
+ curState->u.quantifier.min = GET_ARG(pc);
2698
+ pc += ARG_LEN;
2699
+ curState->u.quantifier.max = GET_ARG(pc);
2700
+ pc += ARG_LEN;
2701
+ minimalquantcommon:
2702
+ curState->index = x->cp - gData->cpbegin;
2703
+ curState->parenSoFar = parenSoFar;
2704
+ PUSH_STATE_STACK(gData);
2705
+ if (curState->u.quantifier.min != 0) {
2706
+ curState->continue_op = REOP_MINIMALREPEAT;
2707
+ curState->continue_pc = pc;
2708
+ /* step over <next> */
2709
+ pc += ARG_LEN;
2710
+ op = (REOp) *pc++;
2711
+ } else {
2712
+ if (!PushBackTrackState(gData, REOP_MINIMALREPEAT,
2713
+ pc, x, x->cp, 0, 0)) {
2714
+ return NULL;
2715
+ }
2716
+ --gData->stateStackTop;
2717
+ pc = pc + GET_OFFSET(pc);
2718
+ op = (REOp) *pc++;
2719
+ }
2720
+ continue;
2721
+
2722
+ case REOP_MINIMALREPEAT:
2723
+ --gData->stateStackTop;
2724
+ --curState;
2725
+
2726
+ if (!result) {
2727
+ /*
2728
+ * Non-greedy failure - try to consume another child.
2729
+ */
2730
+ if (curState->u.quantifier.max == (uint16) -1 ||
2731
+ curState->u.quantifier.max > 0) {
2732
+ curState->index = x->cp - gData->cpbegin;
2733
+ curState->continue_op = REOP_MINIMALREPEAT;
2734
+ curState->continue_pc = pc;
2735
+ pc += ARG_LEN;
2736
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
2737
+ x->parens[k].index = -1;
2738
+ PUSH_STATE_STACK(gData);
2739
+ op = (REOp) *pc++;
2740
+ continue;
2741
+ }
2742
+ /* Don't need to adjust pc since we're going to pop. */
2743
+ break;
2744
+ }
2745
+ if (curState->u.quantifier.min == 0 &&
2746
+ x->cp == gData->cpbegin + curState->index) {
2747
+ /* Matched an empty string, that'll get us nowhere. */
2748
+ result = NULL;
2749
+ break;
2750
+ }
2751
+ if (curState->u.quantifier.min != 0)
2752
+ curState->u.quantifier.min--;
2753
+ if (curState->u.quantifier.max != (uint16) -1)
2754
+ curState->u.quantifier.max--;
2755
+ if (curState->u.quantifier.min != 0) {
2756
+ curState->continue_op = REOP_MINIMALREPEAT;
2757
+ curState->continue_pc = pc;
2758
+ pc += ARG_LEN;
2759
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
2760
+ x->parens[k].index = -1;
2761
+ curState->index = x->cp - gData->cpbegin;
2762
+ PUSH_STATE_STACK(gData);
2763
+ op = (REOp) *pc++;
2764
+ continue;
2765
+ }
2766
+ curState->index = x->cp - gData->cpbegin;
2767
+ curState->parenSoFar = parenSoFar;
2768
+ PUSH_STATE_STACK(gData);
2769
+ if (!PushBackTrackState(gData, REOP_MINIMALREPEAT,
2770
+ pc, x, x->cp,
2771
+ curState->parenSoFar,
2772
+ parenSoFar - curState->parenSoFar)) {
2773
+ return NULL;
2774
+ }
2775
+ --gData->stateStackTop;
2776
+ pc = pc + GET_OFFSET(pc);
2777
+ op = (REOp) *pc++;
2778
+ continue;
2779
+
2780
+ default:
2781
+ JS_ASSERT(JS_FALSE);
2782
+ result = NULL;
2783
+ }
2784
+ break_switch:;
2785
+ }
2786
+ /*
2787
+ * If the match failed and there's a backtrack option, take it.
2788
+ * Otherwise this is a complete and utter failure.
2789
+ */
2790
+ if (!result) {
2791
+ if (gData->cursz == 0)
2792
+ return NULL;
2793
+ backTrackData = gData->backTrackSP;
2794
+ gData->cursz = backTrackData->sz;
2795
+ gData->backTrackSP =
2796
+ (REBackTrackData *) ((char *)backTrackData - backTrackData->sz);
2797
+ x->cp = backTrackData->cp;
2798
+ pc = backTrackData->backtrack_pc;
2799
+ op = backTrackData->backtrack_op;
2800
+ gData->stateStackTop = backTrackData->saveStateStackTop;
2801
+ JS_ASSERT(gData->stateStackTop);
2802
+
2803
+ memcpy(gData->stateStack, backTrackData + 1,
2804
+ sizeof(REProgState) * backTrackData->saveStateStackTop);
2805
+ curState = &gData->stateStack[gData->stateStackTop - 1];
2806
+
2807
+ if (backTrackData->parenCount) {
2808
+ memcpy(&x->parens[backTrackData->parenIndex],
2809
+ (char *)(backTrackData + 1) +
2810
+ sizeof(REProgState) * backTrackData->saveStateStackTop,
2811
+ sizeof(RECapture) * backTrackData->parenCount);
2812
+ parenSoFar = backTrackData->parenIndex + backTrackData->parenCount;
2813
+ } else {
2814
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
2815
+ x->parens[k].index = -1;
2816
+ parenSoFar = curState->parenSoFar;
2817
+ }
2818
+ continue;
2819
+ }
2820
+ x = result;
2821
+
2822
+ /*
2823
+ * Continue with the expression.
2824
+ */
2825
+ op = (REOp)*pc++;
2826
+ }
2827
+ return NULL;
2828
+ }
2829
+
2830
+ static REMatchState *
2831
+ MatchRegExp(REGlobalData *gData, REMatchState *x)
2832
+ {
2833
+ REMatchState *result;
2834
+ const jschar *cp = x->cp;
2835
+ const jschar *cp2;
2836
+ uintN j;
2837
+
2838
+ /*
2839
+ * Have to include the position beyond the last character
2840
+ * in order to detect end-of-input/line condition.
2841
+ */
2842
+ for (cp2 = cp; cp2 <= gData->cpend; cp2++) {
2843
+ gData->skipped = cp2 - cp;
2844
+ x->cp = cp2;
2845
+ for (j = 0; j < gData->regexp->parenCount; j++)
2846
+ x->parens[j].index = -1;
2847
+ result = ExecuteREBytecode(gData, x);
2848
+ if (!gData->ok || result)
2849
+ return result;
2850
+ gData->backTrackSP = gData->backTrackStack;
2851
+ gData->cursz = 0;
2852
+ gData->stateStackTop = 0;
2853
+ cp2 = cp + gData->skipped;
2854
+ }
2855
+ return NULL;
2856
+ }
2857
+
2858
+
2859
+ static REMatchState *
2860
+ InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re)
2861
+ {
2862
+ REMatchState *result;
2863
+ uintN i;
2864
+
2865
+ gData->backTrackStackSize = INITIAL_BACKTRACK;
2866
+ JS_ARENA_ALLOCATE_CAST(gData->backTrackStack, REBackTrackData *,
2867
+ &gData->pool,
2868
+ INITIAL_BACKTRACK);
2869
+ if (!gData->backTrackStack)
2870
+ return NULL;
2871
+ gData->backTrackSP = gData->backTrackStack;
2872
+ gData->cursz = 0;
2873
+
2874
+
2875
+ gData->stateStackLimit = INITIAL_STATESTACK;
2876
+ JS_ARENA_ALLOCATE_CAST(gData->stateStack, REProgState *,
2877
+ &gData->pool,
2878
+ sizeof(REProgState) * INITIAL_STATESTACK);
2879
+ if (!gData->stateStack)
2880
+ return NULL;
2881
+ gData->stateStackTop = 0;
2882
+
2883
+ gData->cx = cx;
2884
+ gData->regexp = re;
2885
+ gData->ok = JS_TRUE;
2886
+
2887
+ JS_ARENA_ALLOCATE_CAST(result, REMatchState *,
2888
+ &gData->pool,
2889
+ sizeof(REMatchState)
2890
+ + (re->parenCount - 1) * sizeof(RECapture));
2891
+ if (!result)
2892
+ return NULL;
2893
+
2894
+ for (i = 0; i < re->classCount; i++)
2895
+ if (!re->classList[i].converted)
2896
+ if (!ProcessCharSet(gData, &re->classList[i]))
2897
+ return NULL;
2898
+
2899
+ return result;
2900
+ }
2901
+
2902
+ JSBool
2903
+ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
2904
+ JSBool test, jsval *rval)
2905
+ {
2906
+ REGlobalData gData;
2907
+ REMatchState *x, *result;
2908
+
2909
+ const jschar *cp, *ep;
2910
+ size_t i, length, start;
2911
+ JSSubString *morepar;
2912
+ JSBool ok;
2913
+ JSRegExpStatics *res;
2914
+ ptrdiff_t matchlen;
2915
+ uintN num, morenum;
2916
+ JSString *parstr, *matchstr;
2917
+ JSObject *obj;
2918
+
2919
+ RECapture *parsub = NULL;
2920
+
2921
+ /*
2922
+ * It's safe to load from cp because JSStrings have a zero at the end,
2923
+ * and we never let cp get beyond cpend.
2924
+ */
2925
+ start = *indexp;
2926
+ length = JSSTRING_LENGTH(str);
2927
+ if (start > length)
2928
+ start = length;
2929
+ cp = JSSTRING_CHARS(str);
2930
+ gData.cpbegin = cp;
2931
+ gData.cpend = cp + length;
2932
+ cp += start;
2933
+ gData.start = start;
2934
+ gData.skipped = 0;
2935
+
2936
+ JS_InitArenaPool(&gData.pool, "RegExpPool", 8096, 4);
2937
+ x = InitMatch(cx, &gData, re);
2938
+ if (!x)
2939
+ return JS_FALSE;
2940
+ x->cp = cp;
2941
+
2942
+ /*
2943
+ * Call the recursive matcher to do the real work. Return null on mismatch
2944
+ * whether testing or not. On match, return an extended Array object.
2945
+ */
2946
+ result = MatchRegExp(&gData, x);
2947
+ ok = gData.ok;
2948
+ if (!ok)
2949
+ goto out;
2950
+ if (!result) {
2951
+ *rval = JSVAL_NULL;
2952
+ goto out;
2953
+ }
2954
+ cp = result->cp;
2955
+ i = PTRDIFF(cp, gData.cpbegin, jschar);
2956
+ *indexp = i;
2957
+ matchlen = i - (start + gData.skipped);
2958
+ ep = cp;
2959
+ cp -= matchlen;
2960
+
2961
+ if (test) {
2962
+ /*
2963
+ * Testing for a match and updating cx->regExpStatics: don't allocate
2964
+ * an array object, do return true.
2965
+ */
2966
+ *rval = JSVAL_TRUE;
2967
+
2968
+ /* Avoid warning. (gcc doesn't detect that obj is needed iff !test); */
2969
+ obj = NULL;
2970
+ } else {
2971
+ /*
2972
+ * The array returned on match has element 0 bound to the matched
2973
+ * string, elements 1 through state.parenCount bound to the paren
2974
+ * matches, an index property telling the length of the left context,
2975
+ * and an input property referring to the input string.
2976
+ */
2977
+ obj = js_NewArrayObject(cx, 0, NULL);
2978
+ if (!obj) {
2979
+ ok = JS_FALSE;
2980
+ goto out;
2981
+ }
2982
+ *rval = OBJECT_TO_JSVAL(obj);
2983
+
2984
+ #define DEFVAL(val, id) { \
2985
+ ok = js_DefineProperty(cx, obj, id, val, \
2986
+ JS_PropertyStub, JS_PropertyStub, \
2987
+ JSPROP_ENUMERATE, NULL); \
2988
+ if (!ok) { \
2989
+ cx->newborn[GCX_OBJECT] = NULL; \
2990
+ cx->newborn[GCX_STRING] = NULL; \
2991
+ goto out; \
2992
+ } \
2993
+ }
2994
+
2995
+ matchstr = js_NewStringCopyN(cx, cp, matchlen, 0);
2996
+ if (!matchstr) {
2997
+ cx->newborn[GCX_OBJECT] = NULL;
2998
+ ok = JS_FALSE;
2999
+ goto out;
3000
+ }
3001
+ DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSVAL(0));
3002
+ }
3003
+
3004
+ res = &cx->regExpStatics;
3005
+ res->input = str;
3006
+ res->parenCount = re->parenCount;
3007
+ if (re->parenCount == 0) {
3008
+ res->lastParen = js_EmptySubString;
3009
+ } else {
3010
+ for (num = 0; num < re->parenCount; num++) {
3011
+ parsub = &result->parens[num];
3012
+ if (num < 9) {
3013
+ if (parsub->index == -1) {
3014
+ res->parens[num].chars = NULL;
3015
+ res->parens[num].length = 0;
3016
+ } else {
3017
+ res->parens[num].chars = gData.cpbegin + parsub->index;
3018
+ res->parens[num].length = parsub->length;
3019
+ }
3020
+ } else {
3021
+ morenum = num - 9;
3022
+ morepar = res->moreParens;
3023
+ if (!morepar) {
3024
+ res->moreLength = 10;
3025
+ morepar = (JSSubString*)
3026
+ JS_malloc(cx, 10 * sizeof(JSSubString));
3027
+ } else if (morenum >= res->moreLength) {
3028
+ res->moreLength += 10;
3029
+ morepar = (JSSubString*)
3030
+ JS_realloc(cx, morepar, res->moreLength *
3031
+ sizeof(JSSubString));
3032
+ }
3033
+ if (!morepar) {
3034
+ cx->newborn[GCX_OBJECT] = NULL;
3035
+ cx->newborn[GCX_STRING] = NULL;
3036
+ ok = JS_FALSE;
3037
+ goto out;
3038
+ }
3039
+ res->moreParens = morepar;
3040
+ if (parsub->index == -1) {
3041
+ morepar[morenum].chars = NULL;
3042
+ morepar[morenum].length = 0;
3043
+ } else {
3044
+ morepar[morenum].chars = gData.cpbegin + parsub->index;
3045
+ morepar[morenum].length = parsub->length;
3046
+ }
3047
+ }
3048
+ if (test)
3049
+ continue;
3050
+ if (parsub->index == -1) {
3051
+ ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
3052
+ JSVAL_VOID, NULL, NULL,
3053
+ JSPROP_ENUMERATE, NULL);
3054
+ } else {
3055
+ parstr = js_NewStringCopyN(cx, gData.cpbegin + parsub->index,
3056
+ parsub->length, 0);
3057
+ if (!parstr) {
3058
+ cx->newborn[GCX_OBJECT] = NULL;
3059
+ cx->newborn[GCX_STRING] = NULL;
3060
+ ok = JS_FALSE;
3061
+ goto out;
3062
+ }
3063
+ ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
3064
+ STRING_TO_JSVAL(parstr), NULL, NULL,
3065
+ JSPROP_ENUMERATE, NULL);
3066
+ }
3067
+ if (!ok) {
3068
+ cx->newborn[GCX_OBJECT] = NULL;
3069
+ cx->newborn[GCX_STRING] = NULL;
3070
+ goto out;
3071
+ }
3072
+ }
3073
+ if (parsub->index == -1) {
3074
+ res->lastParen = js_EmptySubString;
3075
+ } else {
3076
+ res->lastParen.chars = gData.cpbegin + parsub->index;
3077
+ res->lastParen.length = parsub->length;
3078
+ }
3079
+ }
3080
+
3081
+ if (!test) {
3082
+ /*
3083
+ * Define the index and input properties last for better for/in loop
3084
+ * order (so they come after the elements).
3085
+ */
3086
+ DEFVAL(INT_TO_JSVAL(start + gData.skipped),
3087
+ (jsid)cx->runtime->atomState.indexAtom);
3088
+ DEFVAL(STRING_TO_JSVAL(str),
3089
+ (jsid)cx->runtime->atomState.inputAtom);
3090
+ }
3091
+
3092
+ #undef DEFVAL
3093
+
3094
+ res->lastMatch.chars = cp;
3095
+ res->lastMatch.length = matchlen;
3096
+ if (cx->version == JSVERSION_1_2) {
3097
+ /*
3098
+ * JS1.2 emulated Perl4.0.1.8 (patch level 36) for global regexps used
3099
+ * in scalar contexts, and unintentionally for the string.match "list"
3100
+ * psuedo-context. On "hi there bye", the following would result:
3101
+ *
3102
+ * Language while(/ /g){print("$`");} s/ /$`/g
3103
+ * perl4.036 "hi", "there" "hihitherehi therebye"
3104
+ * perl5 "hi", "hi there" "hihitherehi therebye"
3105
+ * js1.2 "hi", "there" "hihitheretherebye"
3106
+ */
3107
+ res->leftContext.chars = JSSTRING_CHARS(str) + start;
3108
+ res->leftContext.length = gData.skipped;
3109
+ } else {
3110
+ /*
3111
+ * For JS1.3 and ECMAv2, emulate Perl5 exactly:
3112
+ *
3113
+ * js1.3 "hi", "hi there" "hihitherehi therebye"
3114
+ */
3115
+ res->leftContext.chars = JSSTRING_CHARS(str);
3116
+ res->leftContext.length = start + gData.skipped;
3117
+ }
3118
+ res->rightContext.chars = ep;
3119
+ res->rightContext.length = gData.cpend - ep;
3120
+
3121
+ out:
3122
+ JS_FinishArenaPool(&gData.pool);
3123
+ return ok;
3124
+ }
3125
+
3126
+ /************************************************************************/
3127
+
3128
+ enum regexp_tinyid {
3129
+ REGEXP_SOURCE = -1,
3130
+ REGEXP_GLOBAL = -2,
3131
+ REGEXP_IGNORE_CASE = -3,
3132
+ REGEXP_LAST_INDEX = -4,
3133
+ REGEXP_MULTILINE = -5
3134
+ };
3135
+
3136
+ #define REGEXP_PROP_ATTRS (JSPROP_PERMANENT|JSPROP_SHARED)
3137
+
3138
+ static JSPropertySpec regexp_props[] = {
3139
+ {"source", REGEXP_SOURCE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
3140
+ {"global", REGEXP_GLOBAL, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
3141
+ {"ignoreCase", REGEXP_IGNORE_CASE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
3142
+ {"lastIndex", REGEXP_LAST_INDEX, REGEXP_PROP_ATTRS,0,0},
3143
+ {"multiline", REGEXP_MULTILINE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
3144
+ {0,0,0,0,0}
3145
+ };
3146
+
3147
+ static JSBool
3148
+ regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3149
+ {
3150
+ jsint slot;
3151
+ JSRegExp *re;
3152
+
3153
+ if (!JSVAL_IS_INT(id))
3154
+ return JS_TRUE;
3155
+ slot = JSVAL_TO_INT(id);
3156
+ if (slot == REGEXP_LAST_INDEX)
3157
+ return JS_GetReservedSlot(cx, obj, 0, vp);
3158
+
3159
+ JS_LOCK_OBJ(cx, obj);
3160
+ re = (JSRegExp *) JS_GetInstancePrivate(cx, obj, &js_RegExpClass, NULL);
3161
+ if (re) {
3162
+ switch (slot) {
3163
+ case REGEXP_SOURCE:
3164
+ *vp = STRING_TO_JSVAL(re->source);
3165
+ break;
3166
+ case REGEXP_GLOBAL:
3167
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_GLOB) != 0);
3168
+ break;
3169
+ case REGEXP_IGNORE_CASE:
3170
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0);
3171
+ break;
3172
+ case REGEXP_MULTILINE:
3173
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0);
3174
+ break;
3175
+ }
3176
+ }
3177
+ JS_UNLOCK_OBJ(cx, obj);
3178
+ return JS_TRUE;
3179
+ }
3180
+
3181
+ static JSBool
3182
+ regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3183
+ {
3184
+ JSBool ok;
3185
+ jsint slot;
3186
+ jsdouble lastIndex;
3187
+
3188
+ ok = JS_TRUE;
3189
+ if (!JSVAL_IS_INT(id))
3190
+ return ok;
3191
+ slot = JSVAL_TO_INT(id);
3192
+ if (slot == REGEXP_LAST_INDEX) {
3193
+ if (!js_ValueToNumber(cx, *vp, &lastIndex))
3194
+ return JS_FALSE;
3195
+ lastIndex = js_DoubleToInteger(lastIndex);
3196
+ ok = js_NewNumberValue(cx, lastIndex, vp) &&
3197
+ JS_SetReservedSlot(cx, obj, 0, *vp);
3198
+ }
3199
+ return ok;
3200
+ }
3201
+
3202
+ /*
3203
+ * RegExp class static properties and their Perl counterparts:
3204
+ *
3205
+ * RegExp.input $_
3206
+ * RegExp.multiline $*
3207
+ * RegExp.lastMatch $&
3208
+ * RegExp.lastParen $+
3209
+ * RegExp.leftContext $`
3210
+ * RegExp.rightContext $'
3211
+ */
3212
+ enum regexp_static_tinyid {
3213
+ REGEXP_STATIC_INPUT = -1,
3214
+ REGEXP_STATIC_MULTILINE = -2,
3215
+ REGEXP_STATIC_LAST_MATCH = -3,
3216
+ REGEXP_STATIC_LAST_PAREN = -4,
3217
+ REGEXP_STATIC_LEFT_CONTEXT = -5,
3218
+ REGEXP_STATIC_RIGHT_CONTEXT = -6
3219
+ };
3220
+
3221
+ JSBool
3222
+ js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res)
3223
+ {
3224
+ JS_ClearRegExpStatics(cx);
3225
+ return js_AddRoot(cx, &res->input, "res->input");
3226
+ }
3227
+
3228
+ void
3229
+ js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res)
3230
+ {
3231
+ if (res->moreParens) {
3232
+ JS_free(cx, res->moreParens);
3233
+ res->moreParens = NULL;
3234
+ }
3235
+ js_RemoveRoot(cx->runtime, &res->input);
3236
+ }
3237
+
3238
+ static JSBool
3239
+ regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3240
+ {
3241
+ jsint slot;
3242
+ JSRegExpStatics *res;
3243
+ JSString *str;
3244
+ JSSubString *sub;
3245
+
3246
+ res = &cx->regExpStatics;
3247
+ if (!JSVAL_IS_INT(id))
3248
+ return JS_TRUE;
3249
+ slot = JSVAL_TO_INT(id);
3250
+ switch (slot) {
3251
+ case REGEXP_STATIC_INPUT:
3252
+ *vp = res->input ? STRING_TO_JSVAL(res->input)
3253
+ : JS_GetEmptyStringValue(cx);
3254
+ return JS_TRUE;
3255
+ case REGEXP_STATIC_MULTILINE:
3256
+ *vp = BOOLEAN_TO_JSVAL(res->multiline);
3257
+ return JS_TRUE;
3258
+ case REGEXP_STATIC_LAST_MATCH:
3259
+ sub = &res->lastMatch;
3260
+ break;
3261
+ case REGEXP_STATIC_LAST_PAREN:
3262
+ sub = &res->lastParen;
3263
+ break;
3264
+ case REGEXP_STATIC_LEFT_CONTEXT:
3265
+ sub = &res->leftContext;
3266
+ break;
3267
+ case REGEXP_STATIC_RIGHT_CONTEXT:
3268
+ sub = &res->rightContext;
3269
+ break;
3270
+ default:
3271
+ sub = REGEXP_PAREN_SUBSTRING(res, slot);
3272
+ break;
3273
+ }
3274
+ str = js_NewStringCopyN(cx, sub->chars, sub->length, 0);
3275
+ if (!str)
3276
+ return JS_FALSE;
3277
+ *vp = STRING_TO_JSVAL(str);
3278
+ return JS_TRUE;
3279
+ }
3280
+
3281
+ static JSBool
3282
+ regexp_static_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3283
+ {
3284
+ JSRegExpStatics *res;
3285
+
3286
+ if (!JSVAL_IS_INT(id))
3287
+ return JS_TRUE;
3288
+ res = &cx->regExpStatics;
3289
+ /* XXX use if-else rather than switch to keep MSVC1.52 from crashing */
3290
+ if (JSVAL_TO_INT(id) == REGEXP_STATIC_INPUT) {
3291
+ if (!JSVAL_IS_STRING(*vp) &&
3292
+ !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
3293
+ return JS_FALSE;
3294
+ }
3295
+ res->input = JSVAL_TO_STRING(*vp);
3296
+ } else if (JSVAL_TO_INT(id) == REGEXP_STATIC_MULTILINE) {
3297
+ if (!JSVAL_IS_BOOLEAN(*vp) &&
3298
+ !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) {
3299
+ return JS_FALSE;
3300
+ }
3301
+ res->multiline = JSVAL_TO_BOOLEAN(*vp);
3302
+ }
3303
+ return JS_TRUE;
3304
+ }
3305
+
3306
+ static JSPropertySpec regexp_static_props[] = {
3307
+ {"input",
3308
+ REGEXP_STATIC_INPUT,
3309
+ JSPROP_ENUMERATE|JSPROP_SHARED,
3310
+ regexp_static_getProperty, regexp_static_setProperty},
3311
+ {"multiline",
3312
+ REGEXP_STATIC_MULTILINE,
3313
+ JSPROP_ENUMERATE|JSPROP_SHARED,
3314
+ regexp_static_getProperty, regexp_static_setProperty},
3315
+ {"lastMatch",
3316
+ REGEXP_STATIC_LAST_MATCH,
3317
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3318
+ regexp_static_getProperty, regexp_static_getProperty},
3319
+ {"lastParen",
3320
+ REGEXP_STATIC_LAST_PAREN,
3321
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3322
+ regexp_static_getProperty, regexp_static_getProperty},
3323
+ {"leftContext",
3324
+ REGEXP_STATIC_LEFT_CONTEXT,
3325
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3326
+ regexp_static_getProperty, regexp_static_getProperty},
3327
+ {"rightContext",
3328
+ REGEXP_STATIC_RIGHT_CONTEXT,
3329
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3330
+ regexp_static_getProperty, regexp_static_getProperty},
3331
+
3332
+ /* XXX should have block scope and local $1, etc. */
3333
+ {"$1", 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3334
+ regexp_static_getProperty, regexp_static_getProperty},
3335
+ {"$2", 1, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3336
+ regexp_static_getProperty, regexp_static_getProperty},
3337
+ {"$3", 2, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3338
+ regexp_static_getProperty, regexp_static_getProperty},
3339
+ {"$4", 3, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3340
+ regexp_static_getProperty, regexp_static_getProperty},
3341
+ {"$5", 4, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3342
+ regexp_static_getProperty, regexp_static_getProperty},
3343
+ {"$6", 5, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3344
+ regexp_static_getProperty, regexp_static_getProperty},
3345
+ {"$7", 6, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3346
+ regexp_static_getProperty, regexp_static_getProperty},
3347
+ {"$8", 7, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3348
+ regexp_static_getProperty, regexp_static_getProperty},
3349
+ {"$9", 8, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
3350
+ regexp_static_getProperty, regexp_static_getProperty},
3351
+
3352
+ {0,0,0,0,0}
3353
+ };
3354
+
3355
+ static void
3356
+ regexp_finalize(JSContext *cx, JSObject *obj)
3357
+ {
3358
+ JSRegExp *re;
3359
+
3360
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
3361
+ if (!re)
3362
+ return;
3363
+ js_DestroyRegExp(cx, re);
3364
+ }
3365
+
3366
+ /* Forward static prototype. */
3367
+ static JSBool
3368
+ regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
3369
+ jsval *rval);
3370
+
3371
+ static JSBool
3372
+ regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
3373
+ {
3374
+ return regexp_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
3375
+ }
3376
+
3377
+ #if JS_HAS_XDR
3378
+
3379
+ #include "jsxdrapi.h"
3380
+
3381
+ static JSBool
3382
+ regexp_xdrObject(JSXDRState *xdr, JSObject **objp)
3383
+ {
3384
+ JSRegExp *re;
3385
+ JSString *source;
3386
+ uint32 flagsword;
3387
+ JSObject *obj;
3388
+
3389
+ if (xdr->mode == JSXDR_ENCODE) {
3390
+ re = (JSRegExp *) JS_GetPrivate(xdr->cx, *objp);
3391
+ if (!re)
3392
+ return JS_FALSE;
3393
+ source = re->source;
3394
+ flagsword = ((uint32)re->cloneIndex << 16) | re->flags;
3395
+ }
3396
+ if (!JS_XDRString(xdr, &source) ||
3397
+ !JS_XDRUint32(xdr, &flagsword)) {
3398
+ return JS_FALSE;
3399
+ }
3400
+ if (xdr->mode == JSXDR_DECODE) {
3401
+ obj = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL);
3402
+ if (!obj)
3403
+ return JS_FALSE;
3404
+ re = js_NewRegExp(xdr->cx, NULL, source, (uint16)flagsword, JS_FALSE);
3405
+ if (!re)
3406
+ return JS_FALSE;
3407
+ if (!JS_SetPrivate(xdr->cx, obj, re) ||
3408
+ !js_SetLastIndex(xdr->cx, obj, 0)) {
3409
+ js_DestroyRegExp(xdr->cx, re);
3410
+ return JS_FALSE;
3411
+ }
3412
+ re->cloneIndex = (uint16)(flagsword >> 16);
3413
+ *objp = obj;
3414
+ }
3415
+ return JS_TRUE;
3416
+ }
3417
+
3418
+ #else /* !JS_HAS_XDR */
3419
+
3420
+ #define regexp_xdrObject NULL
3421
+
3422
+ #endif /* !JS_HAS_XDR */
3423
+
3424
+ static uint32
3425
+ regexp_mark(JSContext *cx, JSObject *obj, void *arg)
3426
+ {
3427
+ JSRegExp *re = (JSRegExp *) JS_GetPrivate(cx, obj);
3428
+ if (re)
3429
+ JS_MarkGCThing(cx, re->source, "source", arg);
3430
+ return 0;
3431
+ }
3432
+
3433
+ JSClass js_RegExpClass = {
3434
+ js_RegExp_str,
3435
+ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
3436
+ JS_PropertyStub, JS_PropertyStub, regexp_getProperty, regexp_setProperty,
3437
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, regexp_finalize,
3438
+ NULL, NULL, regexp_call, NULL,
3439
+ regexp_xdrObject, NULL, regexp_mark, 0
3440
+ };
3441
+
3442
+ static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};
3443
+
3444
+ JSBool
3445
+ js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
3446
+ jsval *rval)
3447
+ {
3448
+ JSRegExp *re;
3449
+ const jschar *source;
3450
+ jschar *chars;
3451
+ size_t length, nflags;
3452
+ uintN flags;
3453
+ JSString *str;
3454
+
3455
+ if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv))
3456
+ return JS_FALSE;
3457
+ JS_LOCK_OBJ(cx, obj);
3458
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
3459
+ if (!re) {
3460
+ JS_UNLOCK_OBJ(cx, obj);
3461
+ *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
3462
+ return JS_TRUE;
3463
+ }
3464
+
3465
+ source = JSSTRING_CHARS(re->source);
3466
+ length = JSSTRING_LENGTH(re->source);
3467
+ if (length == 0) {
3468
+ source = empty_regexp_ucstr;
3469
+ length = sizeof(empty_regexp_ucstr) / sizeof(jschar) - 1;
3470
+ }
3471
+ length += 2;
3472
+ nflags = 0;
3473
+ for (flags = re->flags; flags != 0; flags &= flags - 1)
3474
+ nflags++;
3475
+ chars = (jschar*) JS_malloc(cx, (length + nflags + 1) * sizeof(jschar));
3476
+ if (!chars) {
3477
+ JS_UNLOCK_OBJ(cx, obj);
3478
+ return JS_FALSE;
3479
+ }
3480
+
3481
+ chars[0] = '/';
3482
+ js_strncpy(&chars[1], source, length - 2);
3483
+ chars[length-1] = '/';
3484
+ if (nflags) {
3485
+ if (re->flags & JSREG_GLOB)
3486
+ chars[length++] = 'g';
3487
+ if (re->flags & JSREG_FOLD)
3488
+ chars[length++] = 'i';
3489
+ if (re->flags & JSREG_MULTILINE)
3490
+ chars[length++] = 'm';
3491
+ }
3492
+ JS_UNLOCK_OBJ(cx, obj);
3493
+ chars[length] = 0;
3494
+
3495
+ str = js_NewString(cx, chars, length, 0);
3496
+ if (!str) {
3497
+ JS_free(cx, chars);
3498
+ return JS_FALSE;
3499
+ }
3500
+ *rval = STRING_TO_JSVAL(str);
3501
+ return JS_TRUE;
3502
+ }
3503
+
3504
+ static JSBool
3505
+ regexp_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
3506
+ jsval *rval)
3507
+ {
3508
+ JSString *opt, *str;
3509
+ JSRegExp *oldre, *re;
3510
+ JSBool ok, ok2;
3511
+ JSObject *obj2;
3512
+ size_t length, nbytes;
3513
+ const jschar *cp, *start, *end;
3514
+ jschar *nstart, *ncp, *tmp;
3515
+
3516
+ if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv))
3517
+ return JS_FALSE;
3518
+ opt = NULL;
3519
+ if (argc == 0) {
3520
+ str = cx->runtime->emptyString;
3521
+ } else {
3522
+ if (JSVAL_IS_OBJECT(argv[0])) {
3523
+ /*
3524
+ * If we get passed in a RegExp object we construct a new
3525
+ * RegExp that is a duplicate of it by re-compiling the
3526
+ * original source code. ECMA requires that it be an error
3527
+ * here if the flags are specified. (We must use the flags
3528
+ * from the original RegExp also).
3529
+ */
3530
+ obj2 = JSVAL_TO_OBJECT(argv[0]);
3531
+ if (obj2 && OBJ_GET_CLASS(cx, obj2) == &js_RegExpClass) {
3532
+ if (argc >= 2 && !JSVAL_IS_VOID(argv[1])) { /* 'flags' passed */
3533
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3534
+ JSMSG_NEWREGEXP_FLAGGED);
3535
+ return JS_FALSE;
3536
+ }
3537
+ JS_LOCK_OBJ(cx, obj2);
3538
+ re = (JSRegExp *) JS_GetPrivate(cx, obj2);
3539
+ if (!re) {
3540
+ JS_UNLOCK_OBJ(cx, obj2);
3541
+ return JS_FALSE;
3542
+ }
3543
+ re = js_NewRegExp(cx, NULL, re->source, re->flags, JS_FALSE);
3544
+ JS_UNLOCK_OBJ(cx, obj2);
3545
+ goto created;
3546
+ }
3547
+ }
3548
+ str = js_ValueToString(cx, argv[0]);
3549
+ if (!str)
3550
+ return JS_FALSE;
3551
+ argv[0] = STRING_TO_JSVAL(str);
3552
+ if (argc > 1) {
3553
+ if (JSVAL_IS_VOID(argv[1])) {
3554
+ opt = NULL;
3555
+ } else {
3556
+ opt = js_ValueToString(cx, argv[1]);
3557
+ if (!opt)
3558
+ return JS_FALSE;
3559
+ argv[1] = STRING_TO_JSVAL(opt);
3560
+ }
3561
+ }
3562
+
3563
+ /* Escape any naked slashes in the regexp source. */
3564
+ length = JSSTRING_LENGTH(str);
3565
+ start = JSSTRING_CHARS(str);
3566
+ end = start + length;
3567
+ nstart = ncp = NULL;
3568
+ for (cp = start; cp < end; cp++) {
3569
+ if (*cp == '/' && (cp == start || cp[-1] != '\\')) {
3570
+ nbytes = (++length + 1) * sizeof(jschar);
3571
+ if (!nstart) {
3572
+ nstart = (jschar *) JS_malloc(cx, nbytes);
3573
+ if (!nstart)
3574
+ return JS_FALSE;
3575
+ ncp = nstart + (cp - start);
3576
+ js_strncpy(nstart, start, cp - start);
3577
+ } else {
3578
+ tmp = (jschar *) JS_realloc(cx, nstart, nbytes);
3579
+ if (!tmp) {
3580
+ JS_free(cx, nstart);
3581
+ return JS_FALSE;
3582
+ }
3583
+ ncp = tmp + (ncp - nstart);
3584
+ nstart = tmp;
3585
+ }
3586
+ *ncp++ = '\\';
3587
+ }
3588
+ if (nstart)
3589
+ *ncp++ = *cp;
3590
+ }
3591
+
3592
+ if (nstart) {
3593
+ /* Don't forget to store the backstop after the new string. */
3594
+ JS_ASSERT((size_t)(ncp - nstart) == length);
3595
+ *ncp = 0;
3596
+ str = js_NewString(cx, nstart, length, 0);
3597
+ if (!str) {
3598
+ JS_free(cx, nstart);
3599
+ return JS_FALSE;
3600
+ }
3601
+ argv[0] = STRING_TO_JSVAL(str);
3602
+ }
3603
+ }
3604
+
3605
+ re = js_NewRegExpOpt(cx, NULL, str, opt, JS_FALSE);
3606
+ created:
3607
+ if (!re)
3608
+ return JS_FALSE;
3609
+ JS_LOCK_OBJ(cx, obj);
3610
+ oldre = (JSRegExp *) JS_GetPrivate(cx, obj);
3611
+ ok = JS_SetPrivate(cx, obj, re);
3612
+ ok2 = js_SetLastIndex(cx, obj, 0);
3613
+ JS_UNLOCK_OBJ(cx, obj);
3614
+ if (!ok) {
3615
+ js_DestroyRegExp(cx, re);
3616
+ return JS_FALSE;
3617
+ }
3618
+ if (oldre)
3619
+ js_DestroyRegExp(cx, oldre);
3620
+ *rval = OBJECT_TO_JSVAL(obj);
3621
+ return ok2;
3622
+ }
3623
+
3624
+ static JSBool
3625
+ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
3626
+ JSBool test, jsval *rval)
3627
+ {
3628
+ JSBool ok;
3629
+ JSRegExp *re;
3630
+ jsdouble lastIndex;
3631
+ JSString *str;
3632
+ size_t i;
3633
+
3634
+ ok = JS_InstanceOf(cx, obj, &js_RegExpClass, argv);
3635
+ if (!ok)
3636
+ return JS_FALSE;
3637
+ JS_LOCK_OBJ(cx, obj);
3638
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
3639
+ if (!re) {
3640
+ JS_UNLOCK_OBJ(cx, obj);
3641
+ return JS_TRUE;
3642
+ }
3643
+
3644
+ /* NB: we must reach out: after this paragraph, in order to drop re. */
3645
+ HOLD_REGEXP(cx, re);
3646
+ if (re->flags & JSREG_GLOB) {
3647
+ ok = js_GetLastIndex(cx, obj, &lastIndex);
3648
+ } else {
3649
+ lastIndex = 0;
3650
+ }
3651
+ JS_UNLOCK_OBJ(cx, obj);
3652
+ if (!ok)
3653
+ goto out;
3654
+
3655
+ /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */
3656
+ if (argc == 0) {
3657
+ str = cx->regExpStatics.input;
3658
+ if (!str) {
3659
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3660
+ JSMSG_NO_INPUT,
3661
+ JS_GetStringBytes(re->source),
3662
+ (re->flags & JSREG_GLOB) ? "g" : "",
3663
+ (re->flags & JSREG_FOLD) ? "i" : "",
3664
+ (re->flags & JSREG_MULTILINE) ? "m" : "");
3665
+ ok = JS_FALSE;
3666
+ goto out;
3667
+ }
3668
+ } else {
3669
+ str = js_ValueToString(cx, argv[0]);
3670
+ if (!str)
3671
+ goto out;
3672
+ argv[0] = STRING_TO_JSVAL(str);
3673
+ }
3674
+
3675
+ if (lastIndex < 0 || JSSTRING_LENGTH(str) < lastIndex) {
3676
+ ok = js_SetLastIndex(cx, obj, 0);
3677
+ *rval = JSVAL_NULL;
3678
+ } else {
3679
+ i = (size_t) lastIndex;
3680
+ ok = js_ExecuteRegExp(cx, re, str, &i, test, rval);
3681
+ if (ok && (re->flags & JSREG_GLOB))
3682
+ ok = js_SetLastIndex(cx, obj, (*rval == JSVAL_NULL) ? 0 : i);
3683
+ }
3684
+
3685
+ out:
3686
+ DROP_REGEXP(cx, re);
3687
+ return ok;
3688
+ }
3689
+
3690
+ static JSBool
3691
+ regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
3692
+ {
3693
+ return regexp_exec_sub(cx, obj, argc, argv, JS_FALSE, rval);
3694
+ }
3695
+
3696
+ static JSBool
3697
+ regexp_test(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
3698
+ {
3699
+ if (!regexp_exec_sub(cx, obj, argc, argv, JS_TRUE, rval))
3700
+ return JS_FALSE;
3701
+ if (*rval != JSVAL_TRUE)
3702
+ *rval = JSVAL_FALSE;
3703
+ return JS_TRUE;
3704
+ }
3705
+
3706
+ static JSFunctionSpec regexp_methods[] = {
3707
+ #if JS_HAS_TOSOURCE
3708
+ {js_toSource_str, js_regexp_toString, 0,0,0},
3709
+ #endif
3710
+ {js_toString_str, js_regexp_toString, 0,0,0},
3711
+ {"compile", regexp_compile, 1,0,0},
3712
+ {"exec", regexp_exec, 0,0,0},
3713
+ {"test", regexp_test, 0,0,0},
3714
+ {0,0,0,0,0}
3715
+ };
3716
+
3717
+ static JSBool
3718
+ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
3719
+ {
3720
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
3721
+ /*
3722
+ * If first arg is regexp and no flags are given, just return the arg.
3723
+ * (regexp_compile detects the regexp + flags case and throws a
3724
+ * TypeError.) See 10.15.3.1.
3725
+ */
3726
+ if ((argc < 2 || JSVAL_IS_VOID(argv[1])) &&
3727
+ JSVAL_IS_OBJECT(argv[0]) &&
3728
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[0])) == &js_RegExpClass) {
3729
+ *rval = argv[0];
3730
+ return JS_TRUE;
3731
+ }
3732
+
3733
+ /* Otherwise, replace obj with a new RegExp object. */
3734
+ obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
3735
+ if (!obj)
3736
+ return JS_FALSE;
3737
+ }
3738
+ return regexp_compile(cx, obj, argc, argv, rval);
3739
+ }
3740
+
3741
+ JSObject *
3742
+ js_InitRegExpClass(JSContext *cx, JSObject *obj)
3743
+ {
3744
+ JSObject *proto, *ctor;
3745
+ jsval rval;
3746
+
3747
+ proto = JS_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1,
3748
+ regexp_props, regexp_methods,
3749
+ regexp_static_props, NULL);
3750
+
3751
+ if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
3752
+ return NULL;
3753
+ if (!JS_AliasProperty(cx, ctor, "input", "$_") ||
3754
+ !JS_AliasProperty(cx, ctor, "multiline", "$*") ||
3755
+ !JS_AliasProperty(cx, ctor, "lastMatch", "$&") ||
3756
+ !JS_AliasProperty(cx, ctor, "lastParen", "$+") ||
3757
+ !JS_AliasProperty(cx, ctor, "leftContext", "$`") ||
3758
+ !JS_AliasProperty(cx, ctor, "rightContext", "$'")) {
3759
+ goto bad;
3760
+ }
3761
+
3762
+ /* Give RegExp.prototype private data so it matches the empty string. */
3763
+ if (!regexp_compile(cx, proto, 0, NULL, &rval))
3764
+ goto bad;
3765
+ return proto;
3766
+
3767
+ bad:
3768
+ JS_DeleteProperty(cx, obj, js_RegExpClass.name);
3769
+ return NULL;
3770
+ }
3771
+
3772
+ JSObject *
3773
+ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
3774
+ jschar *chars, size_t length, uintN flags)
3775
+ {
3776
+ JSString *str;
3777
+ JSObject *obj;
3778
+ JSRegExp *re;
3779
+
3780
+ str = js_NewStringCopyN(cx, chars, length, 0);
3781
+ if (!str)
3782
+ return NULL;
3783
+ re = js_NewRegExp(cx, ts, str, flags, JS_FALSE);
3784
+ if (!re)
3785
+ return NULL;
3786
+ obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
3787
+ if (!obj || !JS_SetPrivate(cx, obj, re) || !js_SetLastIndex(cx, obj, 0)) {
3788
+ js_DestroyRegExp(cx, re);
3789
+ return NULL;
3790
+ }
3791
+ return obj;
3792
+ }
3793
+
3794
+ JSObject *
3795
+ js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent)
3796
+ {
3797
+ JSObject *clone;
3798
+ JSRegExp *re;
3799
+
3800
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
3801
+ clone = js_NewObject(cx, &js_RegExpClass, NULL, parent);
3802
+ if (!clone)
3803
+ return NULL;
3804
+ re = JS_GetPrivate(cx, obj);
3805
+ if (!JS_SetPrivate(cx, clone, re) || !js_SetLastIndex(cx, clone, 0)) {
3806
+ cx->newborn[GCX_OBJECT] = NULL;
3807
+ return NULL;
3808
+ }
3809
+ HOLD_REGEXP(cx, re);
3810
+ return clone;
3811
+ }
3812
+
3813
+ JSBool
3814
+ js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex)
3815
+ {
3816
+ jsval v;
3817
+
3818
+ return JS_GetReservedSlot(cx, obj, 0, &v) &&
3819
+ js_ValueToNumber(cx, v, lastIndex);
3820
+ }
3821
+
3822
+ JSBool
3823
+ js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
3824
+ {
3825
+ jsval v;
3826
+
3827
+ return js_NewNumberValue(cx, lastIndex, &v) &&
3828
+ JS_SetReservedSlot(cx, obj, 0, v);
3829
+ }
3830
+
3831
+ #endif /* JS_HAS_REGEXPS */