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