From 0d197330528aac854d1b4d5a3e657d3fca3374c1 Mon Sep 17 00:00:00 2001 From: "rginda%netscape.com" Date: Wed, 7 Feb 2001 21:21:22 +0000 Subject: [PATCH] initial checkin for source reorg. leaf copied mozilla/js/js2 to mozilla/js2/src, mozilla/js/js2/jsc to mozilla/js2/jsc, mozilla/js/js2/tools to mozilla/js2/tools, and mozilla/js/semantics to mozilla/js2/semantics unix now has an autoconf based make system. currently the new make system only makes parser related files, back end stuff to be added soon. mac and windows makesystems will be checked in next. parser.cpp has been factored into token.*, lexer.*, and parser.* utilities.cpp has been factored into formatter.*, exception.*, mem.*, strings.*,ds.h, stlcfg.h, and algo.h git-svn-id: svn://10.0.0.236/trunk@86568 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/AUTHORS | 1 + mozilla/js2/COPYING | 29 + mozilla/js2/ChangeLog | 14 + mozilla/js2/INSTALL | 1 + mozilla/js2/Makefile.am | 2 + mozilla/js2/NEWS | 1 + mozilla/js2/README | 98 + mozilla/js2/TODO | 26 + mozilla/js2/aclocal.m4 | 140 + mozilla/js2/common.mk | 9 + mozilla/js2/config.h.in | 42 + mozilla/js2/configure | 2407 +++++++++ mozilla/js2/configure.in | 57 + mozilla/js2/install-sh | 251 + mozilla/js2/missing | 190 + mozilla/js2/mkinstalldirs | 40 + mozilla/js2/src/Makefile | 71 - mozilla/js2/src/Makefile.am | 44 + mozilla/js2/src/algo.h | 69 + mozilla/js2/src/ds.h | 740 +++ mozilla/js2/src/exception.cpp | 55 +- mozilla/js2/src/exception.h | 115 +- mozilla/js2/src/formatter.cpp | 923 ++++ mozilla/js2/src/formatter.h | 382 ++ mozilla/js2/src/gc_allocator.h | 278 +- mozilla/js2/src/gc_container.h | 102 +- mozilla/js2/src/hash.cpp | 293 +- mozilla/js2/src/hash.h | 645 +-- mozilla/js2/src/ica-exception.cpp | 51 + mozilla/js2/src/ica-exception.h | 115 + mozilla/js2/src/kitchensink.cpp | 95 + mozilla/js2/src/kitchensink.h | 140 + mozilla/js2/src/lexer.cpp | 725 +++ mozilla/js2/src/lexer.h | 125 + mozilla/js2/src/mem.cpp | 181 + mozilla/js2/src/mem.h | 281 ++ mozilla/js2/src/nodefactory.h | 305 +- mozilla/js2/src/numerics.cpp | 4369 ++++++++--------- mozilla/js2/src/numerics.h | 261 +- mozilla/js2/src/parser.cpp | 6491 +++++++++++-------------- mozilla/js2/src/parser.h | 1761 ++++--- mozilla/js2/src/reader.cpp | 216 + mozilla/js2/src/reader.h | 117 + mozilla/js2/src/stlcfg.h | 86 + mozilla/js2/src/strings.cpp | 1466 ++++++ mozilla/js2/src/strings.h | 251 + mozilla/js2/src/systemtypes.h | 67 +- mozilla/js2/src/token.cpp | 362 ++ mozilla/js2/src/token.h | 305 ++ mozilla/js2/src/utilities.cpp | 2653 +--------- mozilla/js2/src/utilities.h | 1550 +----- mozilla/js2/src/world.cpp | 79 +- mozilla/js2/src/world.h | 129 +- mozilla/js2/tests/cpp/Makefile.am | 10 + mozilla/js2/tests/cpp/basics.cpp | 129 + mozilla/js2/tests/cpp/parser_test.cpp | 147 + mozilla/js2/tests/js/calls.js | 85 + mozilla/js2/tests/js/class.xml | 81 + mozilla/js2/tests/js/classes.js | 28 + mozilla/js2/tests/js/constructors.js | 22 + mozilla/js2/tests/js/fields.js | 25 + mozilla/js2/tests/js/methods.js | 16 + mozilla/js2/tests/js/statics.js | 61 + mozilla/js2/tests/js/verify.js | 11 + mozilla/js2/tools/cpp-xref.pl | 138 + 65 files changed, 18069 insertions(+), 11890 deletions(-) create mode 100644 mozilla/js2/AUTHORS create mode 100644 mozilla/js2/COPYING create mode 100644 mozilla/js2/ChangeLog create mode 100644 mozilla/js2/INSTALL create mode 100644 mozilla/js2/Makefile.am create mode 100644 mozilla/js2/NEWS create mode 100644 mozilla/js2/README create mode 100644 mozilla/js2/TODO create mode 100644 mozilla/js2/aclocal.m4 create mode 100644 mozilla/js2/common.mk create mode 100644 mozilla/js2/config.h.in create mode 100755 mozilla/js2/configure create mode 100644 mozilla/js2/configure.in create mode 100755 mozilla/js2/install-sh create mode 100755 mozilla/js2/missing create mode 100755 mozilla/js2/mkinstalldirs delete mode 100644 mozilla/js2/src/Makefile create mode 100644 mozilla/js2/src/Makefile.am create mode 100644 mozilla/js2/src/algo.h create mode 100644 mozilla/js2/src/ds.h create mode 100644 mozilla/js2/src/formatter.cpp create mode 100644 mozilla/js2/src/formatter.h create mode 100644 mozilla/js2/src/ica-exception.cpp create mode 100644 mozilla/js2/src/ica-exception.h create mode 100644 mozilla/js2/src/kitchensink.cpp create mode 100644 mozilla/js2/src/kitchensink.h create mode 100644 mozilla/js2/src/lexer.cpp create mode 100644 mozilla/js2/src/lexer.h create mode 100644 mozilla/js2/src/mem.cpp create mode 100644 mozilla/js2/src/mem.h create mode 100644 mozilla/js2/src/reader.cpp create mode 100644 mozilla/js2/src/reader.h create mode 100644 mozilla/js2/src/stlcfg.h create mode 100644 mozilla/js2/src/strings.cpp create mode 100644 mozilla/js2/src/strings.h create mode 100644 mozilla/js2/src/token.cpp create mode 100644 mozilla/js2/src/token.h create mode 100644 mozilla/js2/tests/cpp/Makefile.am create mode 100644 mozilla/js2/tests/cpp/basics.cpp create mode 100644 mozilla/js2/tests/cpp/parser_test.cpp create mode 100644 mozilla/js2/tests/js/calls.js create mode 100644 mozilla/js2/tests/js/class.xml create mode 100644 mozilla/js2/tests/js/classes.js create mode 100644 mozilla/js2/tests/js/constructors.js create mode 100644 mozilla/js2/tests/js/fields.js create mode 100644 mozilla/js2/tests/js/methods.js create mode 100644 mozilla/js2/tests/js/statics.js create mode 100644 mozilla/js2/tests/js/verify.js create mode 100644 mozilla/js2/tools/cpp-xref.pl diff --git a/mozilla/js2/AUTHORS b/mozilla/js2/AUTHORS new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/mozilla/js2/AUTHORS @@ -0,0 +1 @@ + diff --git a/mozilla/js2/COPYING b/mozilla/js2/COPYING new file mode 100644 index 00000000000..dd29886bbf5 --- /dev/null +++ b/mozilla/js2/COPYING @@ -0,0 +1,29 @@ +The contents of this file are subject to the Netscape Public +License Version 1.1 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of +the License at http://www.mozilla.org/NPL/ + +Software distributed under the License is distributed on an "AS +IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +implied. See the License for the specific language governing +rights and limitations under the License. + +The Original Code is the JavaScript 2 Prototype. + +The Initial Developer of the Original Code is Netscape +Communications Corporation. Portions created by Netscape are +Copyright (C) 1998 Netscape Communications Corporation. All +Rights Reserved. + +Alternatively, the contents of this file may be used under the +terms of the GNU Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. +If you wish to allow use of your version of this file only +under the terms of the GPL and not to allow others to use your +version of this file under the NPL, indicate your decision by +deleting the provisions above and replace them with the notice +and other provisions required by the GPL. If you do not delete +the provisions above, a recipient may use your version of this +file under either the NPL or the GPL. + + diff --git a/mozilla/js2/ChangeLog b/mozilla/js2/ChangeLog new file mode 100644 index 00000000000..42fbb1113b5 --- /dev/null +++ b/mozilla/js2/ChangeLog @@ -0,0 +1,14 @@ +2001-01-30 + + * broke apart some classes contained parser.* and utilities.* into + seperate files. + parser.* begat lexer.*, token.*, reader.* + utilities.* begat mem.*, stlcfg.h, ds.h, strings.*, exception.*, + formatter.*, and algo.h + * parser reorg compile time data: + + new layout: 0:48.01elapsed 86%CPU + old layout: 0:55.85elapsed 57%CPU + + (old layout includes only hash numerics utilities parser world object + files) \ No newline at end of file diff --git a/mozilla/js2/INSTALL b/mozilla/js2/INSTALL new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/mozilla/js2/INSTALL @@ -0,0 +1 @@ + diff --git a/mozilla/js2/Makefile.am b/mozilla/js2/Makefile.am new file mode 100644 index 00000000000..776b947eeea --- /dev/null +++ b/mozilla/js2/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = src tests diff --git a/mozilla/js2/NEWS b/mozilla/js2/NEWS new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/mozilla/js2/NEWS @@ -0,0 +1 @@ + diff --git a/mozilla/js2/README b/mozilla/js2/README new file mode 100644 index 00000000000..d9b698e8e0b --- /dev/null +++ b/mozilla/js2/README @@ -0,0 +1,98 @@ +parse functions + parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, + parseParenthesesAndIdentifierQualifiers(const Token &tParen, + parseQualifiedIdentifier(const Token &t, bool preferRegExp) + parseArrayLiteral(const Token &initialToken) + parseObjectLiteral(const Token &initialToken) + parsePrimaryExpression() + parseMember(ExprNode *target, const Token &tOperator, + parseInvoke(ExprNode *target, uint32 pos, + parsePostfixExpression(bool newExpression) + parseUnaryExpression() + parseExpression(bool noIn, bool noAssignment, bool noComma) + parseParenthesizedExpression() + parseTypeExpression(bool noIn) + parseTypedIdentifier(ExprNode *&type) + parseTypeBinding(Token::Kind kind, bool noIn) + parseTypeListBinding(Token::Kind kind) + parseVariableBinding(bool noQualifiers, bool noIn) + parseFunctionName(FunctionName &fn) + parseFunctionSignature(FunctionDefinition &fd) + parseBlock(bool inSwitch, bool noCloseBrace) + parseBody(SemicolonState *semicolonState) + parseAttributeStatement(uint32 pos, IdentifierList *attributes, + parseAttributesAndStatement(const Token *t, AttributeStatement as, + parseAnnotatedBlock() + parseFor(uint32 pos, SemicolonState &semicolonState) + parseTry(uint32 pos) + parseStatement(bool /*topLevel*/, bool inSwitch, + parseStatementAndSemicolon(SemicolonState &semicolonState) + parseIdentifier() + parseLiteralField() + parseFieldName() + parseArgumentList(NodeQueue &args) + parseArgumentListPrime(NodeQueue &args) + parseNamedArgumentListPrime(NodeQueue &args) + parseAllParameters(FunctionDefinition &fd, + parseOptionalNamedRestParameters (FunctionDefinition &fd, + parseNamedRestParameters(FunctionDefinition &fd, + parseNamedParameters(FunctionDefinition &fd, + parseRestParameter() + parseParameter() + parseOptionalParameter() + parseOptionalParameterPrime(VariableBinding *first) + parseNamedParameter(NodeQueue &aliases) + parseResultSignature() + + +1/28/01 + +Files: + +cpucfg.h + +formatter.cpp formatter.h +"Formatter" class, iostream like wrapper around stdio. + +gc_allocator.h, gc_container.h +boehm gc stuff. + +hash.cpp hash.h +a hash + +lexer.cpp lexer.h +main lexer. + +mem.cpp mem.h +zone, arena, and pool classes for memory management. + +nodefactory.h +parse node factory. + +numerics.cpp numerics.h +numbers and stuff. + +parser.cpp parser.h +main parser source. +tables in parser.h: + enum ExprNode::Kind; types of expressions + enum StmtNode::Kind; types of statements + + +reader.cpp reader.h +"Reader" class, feeds source to the parser/lexer. + +stlcfg.h +stupid stl tricks +. +systemtypes.h +basic typedefs. + +token.cpp token.h +token class. + +utilities.cpp utilities.h +random things. + +world.cpp world.h +the whole world. \ No newline at end of file diff --git a/mozilla/js2/TODO b/mozilla/js2/TODO new file mode 100644 index 00000000000..6a9632b65fd --- /dev/null +++ b/mozilla/js2/TODO @@ -0,0 +1,26 @@ +redo parseAllPArameters code + + +move js/js2 to js2/src +move js/semantics to js2/semantics + +compile on mac and windows + +parser: + +1. Parser is out of date (by 10%?) + a. rework parser to reflect grammer productions. + b. functional attrs. + c. parser node struct changes. + +2. Parser Restructuring (2 weeks.) + +3. Common lisp generator running? + +4. const-ness + a. compile time detection. + b. read before assign. + c. runtime assignment prevention. + d. class/ function/ const equivalence. + +export, namespace, import, package ? \ No newline at end of file diff --git a/mozilla/js2/aclocal.m4 b/mozilla/js2/aclocal.m4 new file mode 100644 index 00000000000..78a4037e5c4 --- /dev/null +++ b/mozilla/js2/aclocal.m4 @@ -0,0 +1,140 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Define a conditional. + +AC_DEFUN(AM_CONDITIONAL, +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + diff --git a/mozilla/js2/common.mk b/mozilla/js2/common.mk new file mode 100644 index 00000000000..427b5b3aa68 --- /dev/null +++ b/mozilla/js2/common.mk @@ -0,0 +1,9 @@ +WFLAGS = -Wmissing-prototypes -Wstrict-prototypes -Wunused \ + -Wswitch + + +if DEBUG +CXXFLAGS = -DXP_UNIX -g -DDEBUG -DNEW_PARSER $(WFLAGS) +else +CXXFLAGS = -DXP_UNIX -O2 -DNEW_PARSER -Wuninitialized $(WFLAGS) +endif diff --git a/mozilla/js2/config.h.in b/mozilla/js2/config.h.in new file mode 100644 index 00000000000..e011b4a19f6 --- /dev/null +++ b/mozilla/js2/config.h.in @@ -0,0 +1,42 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/mozilla/js2/configure b/mozilla/js2/configure new file mode 100755 index 00000000000..2a106794245 --- /dev/null +++ b/mozilla/js2/configure @@ -0,0 +1,2407 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-debug Turn on debugging" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=src/parser.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:558: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:611: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:668: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=JavaScript2 + +VERSION=0.1 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:714: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:727: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:740: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:753: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:766: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) { echo "configure: error: bad value ${enableval} for --enable-debug" 1>&2; exit 1; } ;; +esac +else + debug=false +fi + + + +if test x$debug = xtrue; then + DEBUG_TRUE= + DEBUG_FALSE='#' +else + DEBUG_TRUE='#' + DEBUG_FALSE= +fi + + + + +for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:810: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:842: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 853 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:858: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:884: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:889: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:917: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + +for ac_prog in gawk mawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:953: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:985: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1015: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1066: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1098: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1109 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1114: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1140: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1145: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1173: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1216: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1269: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1290: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1319: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1349: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1370: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1387: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1404: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1429: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1442: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1509: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + + + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1537: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1549: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1570: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1603: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1635: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1665: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1720: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext < addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:1747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1772: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1782: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1811: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1839: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +echo "configure:1864: checking for working mmap" >&5 +if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat > conftest.$ac_ext < +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} + +EOF +if { (eval echo configure:2012: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_mmap_fixed_mapped=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "./Makefile src/Makefile tests/Makefile tests/cpp/Makefile tests/js/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@DEBUG_TRUE@%$DEBUG_TRUE%g +s%@DEBUG_FALSE@%$DEBUG_FALSE%g +s%@CXX@%$CXX%g +s%@AWK@%$AWK%g +s%@CC@%$CC%g +s%@LN_S@%$LN_S%g +s%@RANLIB@%$RANLIB%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/mozilla/js2/configure.in b/mozilla/js2/configure.in new file mode 100644 index 00000000000..3265f5527a0 --- /dev/null +++ b/mozilla/js2/configure.in @@ -0,0 +1,57 @@ +dnl Process this file with autoconf to produce a configure script. + +PACKAGE=JavaScript2 +VERSION=0.1 +AC_INIT(src/parser.h) +AM_INIT_AUTOMAKE(JavaScript2, 0.1) + +AC_ARG_ENABLE(debug, +[ --enable-debug Turn on debugging], +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac],[debug=false]) +AM_CONDITIONAL(DEBUG, test x$debug = xtrue) + +AM_CONFIG_HEADER(config.h) +dnl Checks for programs. +AC_PROG_CXX +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB +dnl AM_PATH_GTK(1.2.0, , +dnl AC_MSG_ERROR(Cannot find GTK: Is gtk-config in path?)) + +dnl Checks for libraries. +dnl Replace `main' with a function in -ldl: +dnl AC_CHECK_LIB(dl, main) +dnl Replace `main' with a function in -lgdk: +dnl AC_CHECK_LIB(gdk, main) +dnl Replace `main' with a function in -lglib: +dnl AC_CHECK_LIB(glib, main) +dnl Replace `main' with a function in -lgmodule: +dnl AC_CHECK_LIB(gmodule, main) +dnl Replace `main' with a function in -lgtk: +dnl AC_CHECK_LIB(gtk, main) +dnl Replace `main' with a function in -lm: +dnl AC_CHECK_LIB(m, main) + +dnl Checks for header files. +AC_HEADER_STDC +dnl AC_CHECK_HEADERS(fcntl.h limits.h malloc.h strings.h unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +dnl AC_C_CONST +dnl AC_C_INLINE +dnl AC_TYPE_SIZE_T + +dnl Checks for library functions. +AC_FUNC_ALLOCA +AC_FUNC_MMAP +dnl AC_CHECK_FUNCS(getcwd getwd putenv strdup strerror tcgetattr) + +AC_OUTPUT(./Makefile src/Makefile tests/Makefile tests/cpp/Makefile tests/js/Makefile) diff --git a/mozilla/js2/install-sh b/mozilla/js2/install-sh new file mode 100755 index 00000000000..e9de23842dc --- /dev/null +++ b/mozilla/js2/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mozilla/js2/missing b/mozilla/js2/missing new file mode 100755 index 00000000000..7789652e877 --- /dev/null +++ b/mozilla/js2/missing @@ -0,0 +1,190 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mozilla/js2/mkinstalldirs b/mozilla/js2/mkinstalldirs new file mode 100755 index 00000000000..97b627128b0 --- /dev/null +++ b/mozilla/js2/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2001-02-07 21:20:46 rginda%netscape.com Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/mozilla/js2/src/Makefile b/mozilla/js2/src/Makefile deleted file mode 100644 index cc119786ec4..00000000000 --- a/mozilla/js2/src/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -CC = gcc -DEFINES += -DDEBUG -CFLAGS = -g -ggdb $(DEFINES) -DDEBUG -DXP_UNIX -Wall -W -Wpointer-arith \ - -Wbad-function-cast -Wstrict-prototypes -Wmissing-prototypes \ - -Wno-non-virtual-dtor - -objs = hash.o \ - icodegenerator.o \ - icodeEmitter.o \ - interpreter.o \ - js2.o \ - jsmath.o \ - jstypes.o \ - numerics.o \ - parser.o \ - utilities.o \ - world.o \ - vmtypes.o \ - debugger.o \ - xmlparser.o \ - icodeasm.o \ - exception.o \ - exception_msgs.o \ - lexutils.o - -test_objs = hash.o \ - icodeasm.o \ - ica_test.o \ - icodegenerator.o \ - icodeEmitter.o \ - interpreter.o \ - jsmath.o \ - jstypes.o \ - numerics.o \ - parser.o \ - utilities.o \ - world.o \ - vmtypes.o \ - xmlparser.o \ - debugger.o \ - exception.o \ - exception_msgs.o \ - lexutils.o - -gc_path = ../../gc/boehm/ - -libs = gc.a -lstdc++ -lm - -%.o : %.cpp - $(CC) -c $(CFLAGS) $< -o $@ - -js2: $(objs) gc.a - $(CC) -o $@ -ggdb $(objs) $(libs) - -gc.a: - (cd $(gc_path) ; ln -f -s Makefile.unix Makefile ; make gc.a) - ln -f -s $(gc_path)gc.a ./gc.a - -gctest: gc_allocator.o - $(CC) -o $@ -ggdb $^ $(libs) - -ica_test: $(test_objs) - $(CC) $(CFLAGS) -o $@ $(test_objs) $(libs) - -clean: - rm -f $(objs) - -depend: - gcc -MM *.cpp > dependencies - -include dependencies diff --git a/mozilla/js2/src/Makefile.am b/mozilla/js2/src/Makefile.am new file mode 100644 index 00000000000..f5b186bb1b8 --- /dev/null +++ b/mozilla/js2/src/Makefile.am @@ -0,0 +1,44 @@ + +include $(top_srcdir)/common.mk + +gc_dir = $(top_srcdir)/../gc/boehm/ + +LIBS = $(gc_dir)/gc.a +INCLUDES = -I$(gc_dir) + +noinst_LIBRARIES = libjs2.a + +libjs2_a_DEPENDENCIES = $(gc_dir)/gc.a +libjs2_a_SOURCES = \ + algo.h \ + cpucfg.h \ + ds.h \ + exception.cpp \ + exception.h \ + formatter.cpp \ + formatter.h \ + gc_allocator.h \ + gc_container.h \ + hash.cpp \ + hash.h \ + lexer.cpp \ + lexer.h \ + mem.cpp \ + mem.h \ + nodefactory.h \ + numerics.cpp \ + numerics.h \ + parser.cpp \ + parser.h \ + reader.cpp \ + reader.h \ + stlcfg.h \ + strings.cpp \ + strings.h \ + systemtypes.h \ + token.cpp \ + token.h \ + utilities.cpp \ + utilities.h \ + world.cpp \ + world.h diff --git a/mozilla/js2/src/algo.h b/mozilla/js2/src/algo.h new file mode 100644 index 00000000000..bfbc485d90a --- /dev/null +++ b/mozilla/js2/src/algo.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef algo_h___ +#define algo_h___ + +namespace JavaScript +{ + +// +// Algorithms +// + +// Assign zero to every element between first inclusive and last +// exclusive. +// This is equivalent ot fill(first, last, 0) but may be more efficient. + template + inline void zero(ForwardIterator first, ForwardIterator last) + { + while (first != last) { + *first = 0; + ++first; + } + } + +// Same as find(first, last, value) but may be more efficient because +// it doesn't use a reference for value. + template + inline InputIterator findValue(InputIterator first, InputIterator last, T value) + { + while (first != last && !(*first == value)) + ++first; + return first; + } + + +} + +#endif /* algo_h___ */ diff --git a/mozilla/js2/src/ds.h b/mozilla/js2/src/ds.h new file mode 100644 index 00000000000..4a672b1f6a3 --- /dev/null +++ b/mozilla/js2/src/ds.h @@ -0,0 +1,740 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef ds_h___ +#define ds_h___ + +#include + +#include "utilities.h" + +namespace JavaScript +{ + +// +// Doubly Linked Lists +// + +// A ListQueue provides insert and delete operations on a doubly-linked list of +// objects threaded through fields named 'next' and 'prev'. The type parameter +// E must be a class derived from ListQueueEntry. +// The ListQueue does not own its elements. They must be deleted explicitly if +// needed. + + struct ListQueueEntry { + ListQueueEntry *next; // Next entry in linked list + ListQueueEntry *prev; // Previous entry in linked list + +#ifdef DEBUG + ListQueueEntry(): next(0), prev(0) {} +#endif + }; + + template + struct ListQueue: private ListQueueEntry { + + ListQueue() {next = this; prev = this;} + + operator bool() const { + // Return true if the ListQueue is nonempty + return next != static_cast(this); + } + + bool operator !() const { + // Return true if the ListQueue is empty + return next == static_cast(this); + } + + E &front() const { + ASSERT(operator bool()); return *static_cast(next); + } + + E &back() const { + ASSERT(operator bool()); return *static_cast(prev); + } + + void push_front(E &elt) { + ASSERT(!elt.next && !elt.prev); + elt.next = next; elt.prev = this; next->prev = &elt; next = &elt; + } + + void push_back(E &elt) { + ASSERT(!elt.next && !elt.prev); + elt.next = this; elt.prev = prev; prev->next = &elt; prev = &elt; + } + + E &pop_front() { + ASSERT(operator bool()); + E *elt = static_cast(next); next = elt->next; next->prev = this; + DEBUG_ONLY(elt->next = 0; elt->prev = 0;) return *elt; + } + + E &pop_back() { + ASSERT(operator bool()); + E *elt = static_cast(prev); prev = elt->prev; prev->next = this; + DEBUG_ONLY(elt->next = 0; elt->prev = 0;); + return *elt; + } + }; + +// +// Growable Arrays +// + +// A Buffer initially points to inline storage of initialSize elements of type T. +// The Buffer can be expanded via the expand method to increase its size by +// allocating storage from the heap. + + template class Buffer { + public: + T *buffer; // Pointer to the current buffer + size_t size; // Current size of the buffer + private: + T initialBuffer[initialSize]; // Initial buffer + public: + Buffer(): buffer(initialBuffer), size(initialSize) {} + ~Buffer() {if (buffer != initialBuffer) delete[] buffer;} + + void expand(size_t newSize); + }; + +// Expand the buffer to size newSize, which must be greater than the current +// size. The buffer's contents are not preserved. + template + inline void Buffer::expand(size_t newSize) { + + ASSERT(newSize > size); + if (buffer != initialBuffer) { + delete[] buffer; + buffer = 0; // For exception safety if the allocation below + // fails. + } + buffer = new T[newSize]; + size = newSize; + } + + + // See ArrayBuffer below. + template class RawArrayBuffer { + T *const cache; // Pointer to a fixed-size cache for holding the buffer + // if it's small enough + protected: + T *buffer; // Pointer to the current buffer + size_t length; // Logical size of the buffer + size_t bufferSize; // Physical size of the buffer +#ifdef DEBUG + size_t maxReservedSize; // Maximum size reserved so far +#endif + + public: + RawArrayBuffer(T *cache, size_t cacheSize) : + cache(cache), buffer(cache), length(0), bufferSize(cacheSize) { + DEBUG_ONLY(maxReservedSize = 0); + } + private: + RawArrayBuffer(const RawArrayBuffer&); // No copy constructor + void operator=(const RawArrayBuffer&); // No assignment operator + public: + ~RawArrayBuffer() {if (buffer != cache) delete[] buffer;} + + private: + void enlarge(size_t newLength); + public: + // Methods that do not expand the buffer cannot throw exceptions. + size_t size() const {return length;} + operator bool() const {return length != 0;} + bool operator !() const {return length == 0;} + + T &front() {ASSERT(length); return *buffer;} + const T &front() const {ASSERT(length); return *buffer;} + T &back() {ASSERT(length); return buffer[length-1];} + const T &back() const {ASSERT(length); return buffer[length-1];} + T *contents() const {return buffer;} + + void reserve(size_t nElts); + T *reserve_back(size_t nElts = 1); + T *advance_back(size_t nElts = 1); + T *reserve_advance_back(size_t nElts = 1); + + void fast_push_back(const T &elt); + void push_back(const T &elt); + void append(const T *elts, size_t nElts); + void append(const T *begin, const T *end) { + ASSERT(end >= begin); + append(begin, static_cast(end - begin)); + } + + T &pop_back() {ASSERT(length); return buffer[--length];} + }; + + +// Enlarge the buffer so that it can hold at least newLength elements. +// May throw an exception, in which case the buffer is left unchanged. + template + void RawArrayBuffer::enlarge(size_t newLength) { + size_t newBufferSize = bufferSize * 2; + if (newBufferSize < newLength) + newBufferSize = newLength; + + auto_ptr newBuffer(new T[newBufferSize]); + T *oldBuffer = buffer; + std::copy(oldBuffer, oldBuffer + length, newBuffer.get()); + buffer = newBuffer.release(); + if (oldBuffer != cache) + delete[] oldBuffer; + bufferSize = newBufferSize; + } + +// Ensure that there is room to hold nElts elements in the buffer, without +// expanding the buffer's logical length. +// May throw an exception, in which case the buffer is left unchanged. + template + inline void RawArrayBuffer::reserve(size_t nElts) { + if (bufferSize < nElts) + enlarge(nElts); +#ifdef DEBUG + if (maxReservedSize < nElts) + maxReservedSize = nElts; +#endif + } + +// Ensure that there is room to hold nElts more elements in the buffer, without +// expanding the buffer's logical length. Return a pointer to the first element +// just past the logical length. +// May throw an exception, in which case the buffer is left unchanged. + template + inline T *RawArrayBuffer::reserve_back(size_t nElts) { + reserve(length + nElts); + return buffer[length]; + } + +// Advance the logical length by nElts, assuming that the memory has previously +// been reserved. +// Return a pointer to the first new element. + template + inline T *RawArrayBuffer::advance_back(size_t nElts) { + ASSERT(length + nElts <= maxReservedSize); + T *p = buffer + length; + length += nElts; + return p; + } + +// Combine the effects of reserve_back and advance_back. + template + inline T *RawArrayBuffer::reserve_advance_back(size_t nElts) { + reserve(length + nElts); + T *p = buffer + length; + length += nElts; + return p; + } + +// Same as push_back but assumes that the memory has previously been reserved. +// May throw an exception if copying elt throws one, in which case the buffer is +// left unchanged. + template + inline void RawArrayBuffer::fast_push_back(const T &elt) { + ASSERT(length < maxReservedSize); + buffer[length] = elt; + ++length; + } + +// Append elt to the back of the buffer. +// May throw an exception, in which case the buffer is left unchanged. + template + inline void RawArrayBuffer::push_back(const T &elt) { + *reserve_back() = elt; + ++length; + } + +// Append nElts elements elts to the back of the array buffer. +// May throw an exception, in which case the buffer is left unchanged. + template + void RawArrayBuffer::append(const T *elts, size_t nElts) { + size_t newLength = length + nElts; + if (newLength > bufferSize) + enlarge(newLength); + std::copy(elts, elts + nElts, buffer + length); + length = newLength; + } + + +// An ArrayBuffer represents an array of elements of type T. The ArrayBuffer +// contains storage for a fixed size array of cacheSize elements; if this size +// is exceeded, the ArrayBuffer allocates the array from the heap. Elements can +// be appended to the back of the array using append. An ArrayBuffer can also +// act as a stack: elements can be pushed and popped from the back. +// +// All ArrayBuffer operations are atomic with respect to exceptions -- either +// they succeed or they do not affect the ArrayBuffer's existing elements and +// length. If T has a constructor, it must have a constructor with no arguments; +// that constructor is called at the time memory for the ArrayBuffer is +// allocated, just like when allocating a regular C++ array. + template + class ArrayBuffer: public RawArrayBuffer { + T cacheArray[cacheSize]; + public: + ArrayBuffer(): RawArrayBuffer(cacheArray, cacheSize) {} + }; + +// +// Bit Sets +// + + template class BitSet { + STATIC_CONST(size_t, nWords = (size+31)>>5); + STATIC_CONST(uint32, lastWordMask = (2u<<((size-1)&31)) - 1); + // Bitmap of bits. The first word contains bits 0(LSB)...31(MSB), + // the second contains bits 32...63, etc. + uint32 words[nWords]; + + public: + void clear() {zero(words, words+nWords);} + BitSet() {clear();} + // Construct a BitSet out of an array of alternating low (inclusive) + // and high (exclusive) ends of ranges of set bits. + // The array is terminated by a 0,0 range. + template explicit BitSet(In a) { + clear(); + size_t low, high; + while (low = *a++, (high = *a++) != 0) setRange(low, high); + } + + bool operator[](size_t i) const { + ASSERT(i < size); + return static_cast(words[i>>5]>>(i&31) & 1); + } + bool none() const; + bool operator==(const BitSet &s) const; + bool operator!=(const BitSet &s) const; + + void set(size_t i) {ASSERT(i < size); words[i>>5] |= 1u<<(i&31);} + void reset(size_t i) {ASSERT(i < size); words[i>>5] &= ~(1u<<(i&31));} + void flip(size_t i) {ASSERT(i < size); words[i>>5] ^= 1u<<(i&31);} + void setRange(size_t low, size_t high); + void resetRange(size_t low, size_t high); + void flipRange(size_t low, size_t high); + }; + +// Return true if all bits are clear. + template + inline bool BitSet::none() const { + if (nWords == 1) + return !words[0]; + else { + const uint32 *w = words; + while (w != words + nWords) + if (*w++) + return false; + return true; + } + } + +// Return true if the BitSets are equal. + template + inline bool BitSet::operator==(const BitSet &s) const { + if (nWords == 1) + return words[0] == s.words[0]; + else + return std::equal(words, s.words); + } + +// Return true if the BitSets are not equal. + template + inline bool BitSet::operator!=(const BitSet &s) const { + return !operator==(s); + } + +// Set all bits between low inclusive and high exclusive. + template + void BitSet::setRange(size_t low, size_t high) { + ASSERT(low <= high && high <= size); + if (low != high) + if (nWords == 1) + words[0] |= (2u<<(high-1)) - (1u<>5); + uint32 *wHigh = words + (high>>5); + uint32 l = 1u << (low&31); + uint32 h = 2u << (high&31); + if (w == wHigh) + *w |= h - l; + else { + *w++ |= -l; + while (w != wHigh) + *w++ = static_cast(-1); + *w |= h - 1; + } + } + } + + // Clear all bits between low inclusive and high exclusive. + template + void BitSet::resetRange(size_t low, size_t high) { + ASSERT(low <= high && high <= size); + if (low != high) + if (nWords == 1) + words[0] &= (1u<>5); + uint32 *wHigh = words + (high>>5); + uint32 l = 1u << (low&31); + uint32 h = 2u << (high&31); + if (w == wHigh) + *w &= l - 1 - h; + else { + *w++ &= l - 1; + while (w != wHigh) + *w++ = 0; + *w &= -h; + } + } + } + + // Invert all bits between low inclusive and high exclusive. + template + void BitSet::flipRange(size_t low, size_t high) { + ASSERT(low <= high && high <= size); + if (low != high) + if (nWords == 1) + words[0] ^= (2u<<(high-1)) - (1u<>5); + uint32 *wHigh = words + (high>>5); + uint32 l = 1u << (low&31); + uint32 h = 2u << (high&31); + if (w == wHigh) + *w ^= h - l; + else { + *w++ ^= -l; + while (w != wHigh) + *w++ ^= static_cast(-1); + *w ^= h - 1; + } + } + } + + +// +// Array Queues +// + + // See ArrayQueue below. + template class RawArrayQueue { + T *const cache; // Pointer to a fixed-size cache for holding the buffer + // if it's small enough + protected: + T *buffer; // Pointer to the current buffer + T *bufferEnd; // Pointer to the end of the buffer + T *f; // Front end of the circular buffer, used for reading + // elements; buffer <= f < bufferEnd + T *b; // Back end of the circular buffer, used for writing + // elements; buffer < b <= bufferEnd + size_t length; // Number of elements used in the circular buffer + size_t bufferSize; // Physical size of the buffer +#ifdef DEBUG + size_t maxReservedSize; // Maximum size reserved so far +#endif + + public: + RawArrayQueue(T *cache, size_t cacheSize) : + cache(cache), buffer(cache), bufferEnd(cache + cacheSize), + f(cache), b(cache), length(0), bufferSize(cacheSize) { + DEBUG_ONLY(maxReservedSize = 0); + } + private: + RawArrayQueue(const RawArrayQueue&); // No copy constructor + void operator=(const RawArrayQueue&); // No assignment operator + public: + ~RawArrayQueue() {if (buffer != cache) delete[] buffer;} + + private: + void enlarge(size_t newLength); + public: + + // Methods that do not expand the buffer cannot throw exceptions. + size_t size() const {return length;} + operator bool() const {return length != 0;} + bool operator !() const {return length == 0;} + + T &front() {ASSERT(length); return *f;} + const T &front() const {ASSERT(length); return *f;} + T &back() {ASSERT(length); return b[-1];} + const T &back() const {ASSERT(length); return b[-1];} + + T &pop_front() { + ASSERT(length); + --length; T &elt = *f++; + if (f == bufferEnd) + f = buffer; + return elt; + } + + size_t pop_front(size_t nElts, T *&begin, T *&end); + + T &pop_back() { + ASSERT(length); + --length; + T &elt = *--b; + if (b == buffer) + b = bufferEnd; + return elt; + } + + void reserve_back(); + void reserve_back(size_t nElts); + T *advance_back(); + T *advance_back(size_t nElts, size_t &nEltsAdvanced); + + void fast_push_back(const T &elt); + void push_back(const T &elt); + + // Same as append but assumes that memory has previously been reserved. + // Does not throw exceptions. T::operator= must not throw exceptions. + template + void fast_append(InputIter begin, InputIter end) { + size_t nElts = static_cast(std::distance(begin, end)); + ASSERT(length + nElts <= maxReservedSize); + while (nElts) { + size_t nEltsAdvanced; + T *dst = advance_back(nElts, nEltsAdvanced); + nElts -= nEltsAdvanced; + while (nEltsAdvanced--) { + *dst = *begin; ++dst; ++begin; + } + } + } + + // Append elements from begin to end to the back of the queue. + // T::operator= must not throw exceptions. + // reserve_back may throw an exception, in which case the queue is left + // unchanged. + template void append(InputIter begin, InputIter end) { + size_t nElts = static_cast(std::distance(begin, end)); + reserve_back(nElts); + while (nElts) { + size_t nEltsAdvanced; + T *dst = advance_back(nElts, nEltsAdvanced); + nElts -= nEltsAdvanced; + while (nEltsAdvanced--) { + *dst = *begin; ++dst; ++begin; + } + } + } + }; + +// Pop between one and nElts elements from the front of the queue. Set begin +// and end to an array of the first n elements, where n is the return value. +// The popped elements may be accessed until the next non-const operation. +// Does not throw exceptions. + template + size_t RawArrayQueue::pop_front(size_t nElts, T *&begin, T *&end) { + ASSERT(nElts <= length); + begin = f; + size_t eltsToEnd = static_cast(bufferEnd - f); + if (nElts < eltsToEnd) { + length -= nElts; + f += nElts; + end = f; + return nElts; + } else { + length -= eltsToEnd; + end = bufferEnd; + f = buffer; + return eltsToEnd; + } + } + + // Enlarge the buffer so that it can hold at least newLength elements. + // May throw an exception, in which case the queue is left unchanged. + template + void RawArrayQueue::enlarge(size_t newLength) { + size_t newBufferSize = bufferSize * 2; + if (newBufferSize < newLength) + newBufferSize = newLength; + + auto_ptr newBuffer(new T[newBufferSize]); + T *oldBuffer = buffer; + size_t eltsToEnd = static_cast(bufferEnd - f); + if (eltsToEnd <= length) + std::copy(f, f + eltsToEnd, newBuffer.get()); + else { + std::copy(f, bufferEnd, newBuffer.get()); + std::copy(oldBuffer, b, newBuffer.get() + eltsToEnd); + } + buffer = newBuffer.release(); + f = buffer; + b = buffer + length; + if (oldBuffer != cache) + delete[] oldBuffer; + bufferSize = newBufferSize; + } + +// Ensure that there is room to hold one more element at the back of the queue, +// without expanding the queue's logical length. +// May throw an exception, in which case the queue is left unchanged. + template + inline void RawArrayQueue::reserve_back() { + if (length == bufferSize) + enlarge(length + 1); +#ifdef DEBUG + if (maxReservedSize <= length) + maxReservedSize = length + 1; +#endif + } + +// Ensure that there is room to hold nElts more elements at the back of the +// queue, without expanding the queue's logical length. +// May throw an exception, in which case the queue is left unchanged. + template + inline void RawArrayQueue::reserve_back(size_t nElts) { + nElts += length; + if (bufferSize < nElts) + enlarge(nElts); +#ifdef DEBUG + if (maxReservedSize < nElts) + maxReservedSize = nElts; +#endif + } + +// Advance the back of the queue by one element, assuming that the memory has +// previously been reserved. +// Return a pointer to that new element. +// Does not throw exceptions. + template + inline T *RawArrayQueue::advance_back() { + ASSERT(length < maxReservedSize); + ++length; + if (b == bufferEnd) + b = buffer; + return b++; + } + +// Advance the back of the queue by between one and nElts elements and return a +// pointer to them, assuming that the memory has previously been reserved. +// nEltsAdvanced gets the actual number of elements advanced. +// Does not throw exceptions. + template + T *RawArrayQueue::advance_back(size_t nElts, size_t &nEltsAdvanced) { + size_t newLength = length + nElts; + ASSERT(newLength <= maxReservedSize); + if (nElts) { + T *b2 = b; + if (b2 == bufferEnd) + b2 = buffer; + + size_t room = static_cast(bufferEnd - b2); + if (nElts > room) { + nElts = room; + newLength = length + nElts; + } + length = newLength; + nEltsAdvanced = nElts; + b = b2 + nElts; + return b2; + } else { + nEltsAdvanced = 0; + return 0; + } + } + +// Same as push_back but assumes that the memory has previously been reserved. +// May throw an exception if copying elt throws one, in which case the queue is +// left unchanged. + template + inline void RawArrayQueue::fast_push_back(const T &elt) { + ASSERT(length < maxReservedSize); + T *b2 = b; + if (b2 == bufferEnd) + b2 = buffer; + *b2 = elt; + b = b2 + 1; + ++length; + } + +// Append elt to the back of the queue. +// May throw an exception, in which case the queue is left unchanged. + template + inline void RawArrayQueue::push_back(const T &elt) { + reserve_back(); + T *b2 = b == bufferEnd ? buffer : b; + *b2 = elt; + b = b2 + 1; + ++length; + } + + +// An ArrayQueue represents an array of elements of type T that can be written +// at its back end and read at its front or back end. In addition, arrays of +// multiple elements may be written at the back end or read at the front end. +// The ArrayQueue contains storage for a fixed size array of cacheSize elements; +// if this size is exceeded, the ArrayQueue allocates the array from the heap. + template + class ArrayQueue: public RawArrayQueue { + T cacheArray[cacheSize]; + public: + ArrayQueue(): RawArrayQueue(cacheArray, cacheSize) {} + }; + +// +// Array auto_ptr's +// + +// An ArrayAutoPtr holds a pointer to an array initialized by new T[x]. +// A regular auto_ptr cannot be used here because it deletes its pointer using +// delete rather than delete[]. +// An appropriate operator[] is also provided. + template class ArrayAutoPtr { + T *ptr; + + public: + explicit ArrayAutoPtr(T *p = 0): ptr(p) {} + ArrayAutoPtr(ArrayAutoPtr &a): ptr(a.ptr) {a.ptr = 0;} + ArrayAutoPtr &operator=(ArrayAutoPtr &a) {reset(a.release());} + ~ArrayAutoPtr() {delete[] ptr;} + + T &operator*() const {return *ptr;} + T &operator->() const {return *ptr;} + template T &operator[](N i) const {return ptr[i];} + T *get() const {return ptr;} + T *release() {T *p = ptr; ptr = 0; return p;} + void reset(T *p = 0) {delete[] ptr; ptr = p;} + }; + + typedef ArrayAutoPtr CharAutoPtr; + +} + +#endif /* ds_h___ */ diff --git a/mozilla/js2/src/exception.cpp b/mozilla/js2/src/exception.cpp index 7c5a7d08c01..ff51b6033a1 100644 --- a/mozilla/js2/src/exception.cpp +++ b/mozilla/js2/src/exception.cpp @@ -31,21 +31,54 @@ * file under either the NPL or the GPL. */ +#include + #include "exception.h" -namespace JavaScript { - - extern const char* exception_types[]; - extern const char* exception_msgs[]; +namespace JavaScript +{ - void - JSException::toString8 (string8 &rval) +// +// Exceptions +// + + + static const char *const kindStrings[] = { + "Syntax error", // syntaxError + "Stack overflow" // stackOverflow + }; + +// Return a null-terminated string describing the exception's kind. + const char * + Exception::kindString() const { - rval = string8(exception_types[mType]) + " Exception: " + - string8(exception_msgs[mID]); - if (mSource.size() != 0) - rval += " in " + mSource; + return kindStrings[kind]; + } + + +// Return the full error message. + String + Exception::fullMessage() const + { + String m(widenCString("In ")); + m += sourceFile; + if (lineNum) { + char b[32]; + sprintf(b, ", line %d:\n", lineNum); + m += b; + m += sourceLine; + m += '\n'; + String sourceLine2(sourceLine); + insertChars(sourceLine2, charNum, "[ERROR]"); + m += sourceLine2; + m += '\n'; + } else + m += ":\n"; + m += kindString(); + m += ": "; + m += message; + m += '\n'; + return m; } } - diff --git a/mozilla/js2/src/exception.h b/mozilla/js2/src/exception.h index 4fed93e905c..2a27585ad0e 100644 --- a/mozilla/js2/src/exception.h +++ b/mozilla/js2/src/exception.h @@ -33,83 +33,60 @@ #ifndef exception_h___ #define exception_h___ -#include "utilities.h" -namespace JavaScript { +#include "strings.h" - enum ExceptionType { - etUnknown = 0, - etLexer, - etParser, - etRuntime, - etCount - }; +namespace JavaScript +{ - enum ExceptionID { - eidExpectBool = 0, - eidExpectDouble, - eidExpectInt32, - eidExpectUInt32, - eidExpectRegister, - eidExpectArgList, - eidExpectColon, - eidExpectCloseParen, - eidExpectBinaryOp, - eidExpectString, - eidExpectLabel, - eidExpectComma, - eidExpectNewline, - eidExpectIdentifier, - eidDuplicateLabel, - eidUnknownICode, - eidUnknownBinaryOp, - eidUnterminatedString, - eidCount - }; - - class JSException { - public: - JSException (ExceptionID ID, string8_citer pos = 0, - string8 source = "", ExceptionType type = etUnknown) - : mID(ID), mType(type), mPos(pos), mSource(source) {} - ExceptionID mID; - ExceptionType mType; - string8_citer mPos; - string8 mSource; +// +// Exceptions +// - public: - void toString8(string8 &rval); - /* - private: - JSException(const JSException&); - */ +// A JavaScript exception (other than out-of-memory, for which we use the +// standard C++ exception bad_alloc). + struct Exception { + enum Kind { + syntaxError, + stackOverflow + }; + Kind kind; // The exception's kind + String message; // The detailed message + String sourceFile; // A description of the source code that caused the + // error + uint32 lineNum; // Number of line that caused the error + uint32 charNum; // Character offset within the line that caused the + // error + uint32 pos; // Offset within the input of the error + String sourceLine; // The text of the source line + + Exception (Kind kind, const String &message) : + kind(kind), message(message), lineNum(0), charNum(0) {} + + Exception(Kind kind, const String &message, const String &sourceFile, + uint32 lineNum, uint32 charNum, uint32 pos, + const String &sourceLine) : + kind(kind), message(message), sourceFile(sourceFile), + lineNum(lineNum), charNum(charNum), pos(pos), sourceLine(sourceLine) + {} + + Exception(Kind kind, const String &message, const String &sourceFile, + uint32 lineNum, uint32 charNum, uint32 pos, + const char16 *sourceLineBegin, const char16 *sourceLineEnd) : + kind(kind), message(message), sourceFile(sourceFile), + lineNum(lineNum), charNum(charNum), pos(pos), + sourceLine(sourceLineBegin, sourceLineEnd) {} + + bool hasKind(Kind k) const {return kind == k;} + const char *kindString() const; + String fullMessage() const; }; - class JSLexException : public JSException { - public: - JSLexException (ExceptionID ID, string8_citer pos = 0, - string8 source = "") : - JSException(ID, pos, source, etLexer) {} - /* - private: - JSLexException (const JSLexException&); - */ - }; - - class JSParseException : public JSException { - public: - JSParseException (ExceptionID ID, string8_citer pos = 0, - string8 source = "") : - JSException(ID, pos, source, etParser) {} - /* - private: - JSParseException (const JSParseException&); - */ - }; + +// Throw a stackOverflow exception if the execution stack has gotten too large. + inline void checkStackSize() {} } #endif /* exception_h___ */ - - diff --git a/mozilla/js2/src/formatter.cpp b/mozilla/js2/src/formatter.cpp new file mode 100644 index 00000000000..c7f5d4a80b1 --- /dev/null +++ b/mozilla/js2/src/formatter.cpp @@ -0,0 +1,923 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include "algo.h" +#include "formatter.h" + +namespace JavaScript +{ + static const char controlCharNames[6] = {'b', 't', 'n', 'v', 'f', 'r'}; + +// Print the characters from begin to end, escaping them as necessary to make +// the resulting string be readable if placed between two quotes specified by +// quote (which should be either '\'' or '"'). + void + escapeString(Formatter &f, const char16 *begin, const char16 *end, + char16 quote) + { + ASSERT(begin <= end); + + const char16 *chunk = begin; + while (begin != end) { + char16 ch = *begin++; + CharInfo ci(ch); + if (char16Value(ch) < 0x20 || isLineBreak(ci) || isFormat(ci) + || ch == '\\' || ch == quote) { + if (begin-1 != chunk) + printString(f, chunk, begin-1); + chunk = begin; + + f << '\\'; + switch (ch) { + case 0x0008: + case 0x0009: + case 0x000A: + case 0x000B: + case 0x000C: + case 0x000D: + f << controlCharNames[ch - 0x0008]; + break; + + case '\'': + case '"': + case '\\': + f << ch; + break; + + case 0x0000: + if (begin == end || char16Value(*begin) < '0' || + char16Value(*begin) > '9') { + f << '0'; + break; + } + default: + if (char16Value(ch) <= 0xFF) { + f << 'x'; + printHex(f, + static_cast(char16Value(ch)), + 2); + } else { + f << 'u'; + printHex(f, + static_cast(char16Value(ch)), + 4); + } + } + } + } + if (begin != chunk) + printString(f, chunk, begin); + } + + +// Print s as a quoted string using the given quotes (which should be +// either '\'' or '"'). + void + quoteString(Formatter &f, const String &s, char16 quote) + { + f << quote; + const char16 *begin = s.data(); + escapeString(f, begin, begin + s.size(), quote); + f << quote; + } + +#ifdef XP_MAC_MPW +// Macintosh MPW replacements for the ANSI routines. These translate LF's to +// CR's because the MPW libraries supplied by Metrowerks don't do that for some +// reason. + static void + translateLFtoCR(char *begin, char *end) + { + while (begin != end) { + if (*begin == '\n') + *begin = '\r'; + ++begin; + } + } + + size_t + printChars(FILE *file, const char *begin, const char *end) + { + ASSERT(end >= begin); + size_t n = static_cast(end - begin); + size_t extra = 0; + char buffer[1024]; + + while (n > sizeof buffer) { + std::memcpy(buffer, begin, sizeof buffer); + translateLFtoCR(buffer, buffer + sizeof buffer); + extra += fwrite(buffer, 1, sizeof buffer, file); + n -= sizeof buffer; + begin += sizeof buffer; + } + std::memcpy(buffer, begin, n); + translateLFtoCR(buffer, buffer + n); + return extra + fwrite(buffer, 1, n, file); + } + + int + std::fputc(int c, FILE *file) + { + char buffer = static_cast(c); + if (buffer == '\n') + buffer = '\r'; + return static_cast(fwrite(&buffer, 1, 1, file)); + } + + int + std::fputs(const char *s, FILE *file) + { + return static_cast(printChars(file, s, s + strlen(s))); + } + + int + std::fprintf(FILE* file, const char *format, ...) + { + Buffer b; + + while (true) { + va_list args; + va_start(args, format); + int n = vsnprintf(b.buffer, b.size, format, args); + va_end(args); + if (n >= 0 && n < b.size) { + translateLFtoCR(b.buffer, b.buffer + n); + return static_cast(fwrite(b.buffer, 1, + static_cast(n), file)); + } + b.expand(b.size*2); + } + } + +#endif // XP_MAC_MPW + +// Write ch. + void + Formatter::printChar8(char ch) + { + printStr8(&ch, &ch + 1); + } + + +// Write ch. + void + Formatter::printChar16(char16 ch) + { + printStr16(&ch, &ch + 1); + } + + +// Write the null-terminated string str. + void + Formatter::printZStr8(const char *str) + { + printStr8(str, str + strlen(str)); + } + + +// Write the String s. + void + Formatter::printString16(const String &s) + { + const char16 *begin = s.data(); + printStr16(begin, begin + s.size()); + } + + +// Write the printf format using the supplied args. + void + Formatter::printVFormat8(const char *format, va_list args) + { + Buffer b; + + while (true) { + int n = vsnprintf(b.buffer, b.size, format, args); + if (n >= 0 && static_cast(n) < b.size) { + printStr8(b.buffer, b.buffer + n); + return; + } + b.expand(b.size*2); + } + } + + + static const int printCharBufferSize = 64; + +// Print ch count times. + void + printChar(Formatter &f, char ch, int count) + { + char str[printCharBufferSize]; + + while (count > 0) { + int c = count; + if (c > printCharBufferSize) + c = printCharBufferSize; + count -= c; + STD::memset(str, ch, static_cast(c)); + printString(f, str, str+c); + } + } + + +// Print ch count times. + void + printChar(Formatter &f, char16 ch, int count) + { + char16 str[printCharBufferSize]; + + while (count > 0) { + int c = count; + if (c > printCharBufferSize) + c = printCharBufferSize; + count -= c; + char16 *strEnd = str + c; + std::fill(str, strEnd, ch); + printString(f, str, strEnd); + } + } + + +// Print i using the given formatting string, padding on the left with pad +// characters to use at least nDigits characters. + void + printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format) + { + char str[20]; + int n = sprintf(str, format, i); + if (n < nDigits) + printChar(f, pad, nDigits - n); + printString(f, str, str+n); + } + + +// Print p as a pointer. + void + printPtr(Formatter &f, void *p) + { + char str[20]; + int n = sprintf(str, "%p", p); + printString(f, str, str+n); + } + + +// printf formats for printing non-ASCII characters on an ASCII stream +#ifdef XP_MAC + static const char unprintableFormat[] = "\xC7%.4X\xC8"; // Use angle quotes +#elif defined _WIN32 + static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes +#else + static const char unprintableFormat[] = "<%.4X>"; +#endif + + + static const uint16 defaultFilterRanges[] = { + 0x00, 0x09, // Filter all control characters except \t and \n + 0x0B, 0x20, + 0x7F, 0x100, // Filter all non-ASCII characters + 0, 0 + }; + + BitSet<256> AsciiFileFormatter::defaultFilter(defaultFilterRanges); + + +// Construct an AsciiFileFormatter using the given file and filter f. +// If f is nil, use the default filter. + AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *f): + file(file) +#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug + , filter(f ? *f : defaultFilter) +#endif + { +#ifdef _WIN32 // Microsoft Visual C++ 6.0 bug + if (f) + filter = *f; + else + filter = defaultFilter; +#endif + filterEmpty = filter.none(); + } + + +// Write ch, escaping non-ASCII characters. + void + AsciiFileFormatter::printChar8(char ch) + { + if (filterChar(ch)) + fprintf(file, unprintableFormat, static_cast(ch)); + else + fputc(ch, file); + } + + +// Write ch, escaping non-ASCII characters. + void + AsciiFileFormatter::printChar16(char16 ch) + { + if (filterChar(ch)) + fprintf(file, unprintableFormat, char16Value(ch)); + else + fputc(static_cast(ch), file); + } + + +// Write the null-terminated string str, escaping non-ASCII characters. + void + AsciiFileFormatter::printZStr8(const char *str) + { + if (filterEmpty) + fputs(str, file); + else + printStr8(str, str + strlen(str)); + } + + +// Write the string between strBegin and strEnd, escaping non-ASCII characters. + void + AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd) + { + if (filterEmpty) + printChars(file, strBegin, strEnd); + else { + ASSERT(strEnd >= strBegin); + const char *p = strBegin; + while (strBegin != strEnd) { + char ch = *strBegin; + if (filterChar(ch)) { + if (p != strBegin) { + printChars(file, p, strBegin); + p = strBegin; + } + fprintf(file, unprintableFormat, static_cast(ch)); + } + ++strBegin; + } + if (p != strBegin) + printChars(file, p, strBegin); + } + } + +// Write the string between strBegin and strEnd, escaping non-ASCII characters. + void + AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) + { + char buffer[512]; + + ASSERT(strEnd >= strBegin); + char *q = buffer; + while (strBegin != strEnd) { + char16 ch = *strBegin++; + if (filterChar(ch)) { + if (q != buffer) { + printChars(file, buffer, q); + q = buffer; + } + fprintf(file, unprintableFormat, char16Value(ch)); + } else { + *q++ = static_cast(ch); + if (q == buffer + sizeof buffer) { + printChars(file, buffer, buffer + sizeof buffer); + q = buffer; + } + } + } + if (q != buffer) + printChars(file, buffer, q); + } + + AsciiFileFormatter stdOut(stdout); + AsciiFileFormatter stdErr(stderr); + + +// Write ch. + void + StringFormatter::printChar8(char ch) + { + s += ch; + } + + +// Write ch. + void + StringFormatter::printChar16(char16 ch) + { + s += ch; + } + + +// Write the null-terminated string str. + void + StringFormatter::printZStr8(const char *str) + { + s += str; + } + + +// Write the string between strBegin and strEnd. + void + StringFormatter::printStr8(const char *strBegin, const char *strEnd) + { + appendChars(s, strBegin, strEnd); + } + + +// Write the string between strBegin and strEnd. + void + StringFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) + { + s.append(strBegin, strEnd); + } + + +// Write the String str. + void + StringFormatter::printString16(const String &str) + { + s += str; + } + + +// +// Formatted Output +// + +// See "Prettyprinting" by Derek Oppen in ACM Transactions on Programming +// Languages and Systems 2:4, October 1980, pages 477-482 for the algorithm. + +// The default line width for pretty printing + uint32 PrettyPrinter::defaultLineWidth = 20; + + +// Create a PrettyPrinter that outputs to Formatter f. The PrettyPrinter +// breaks lines at optional breaks so as to try not to exceed lines of width +// lineWidth, although it may not always be able to do so. Formatter f should +// be at the beginning of a line. Call end before destroying the Formatter; +// otherwise the last line may not be output to f. + PrettyPrinter::PrettyPrinter(Formatter &f, uint32 lineWidth): + lineWidth(min(lineWidth, unlimitedLineWidth)), + outputFormatter(f), + outputPos(0), + lineNum(0), + lastBreak(0), + margin(0), + nNestedBlocks(0), + leftSerialPos(0), + rightSerialPos(0), + itemPool(20) + { +#ifdef DEBUG + topRegion = 0; +#endif + } + + +// Destroy the PrettyPrinter. Because it's a very bad idea for a destructor to +// throw exceptions, this destructor does not flush any buffered output. Call +// end just before destroying the PrettyPrinter to do that. + PrettyPrinter::~PrettyPrinter() + { + ASSERT(!topRegion && !nNestedBlocks); + } + + +// Output either a line break (if sameLine is false) or length spaces (if +// sameLine is true). Also advance leftSerialPos by length. +// +// If this method throws an exception, it is guaranteed to already have updated +// all of the PrettyPrinter state; all that might be missing would be some +// output to outputFormatter. + void + PrettyPrinter::outputBreak(bool sameLine, uint32 length) + { + leftSerialPos += length; + + if (sameLine) { + outputPos += length; + // Exceptions may be thrown below. + printChar(outputFormatter, ' ', static_cast(length)); + } else { + lastBreak = ++lineNum; + outputPos = margin; + // Exceptions may be thrown below. + outputFormatter << '\n'; + printChar(outputFormatter, ' ', static_cast(margin)); + } + } + + +// Check to see whether (rightSerialPos+rightOffset)-leftSerialPos has gotten so large that we may pop items +// off the left end of activeItems because their totalLengths are known to be larger than the +// amount of space left on the current line. +// Return true if there are any items left on activeItems. +// +// If this method throws an exception, it leaves the PrettyPrinter in a consistent state, having +// atomically popped off one or more items from the left end of activeItems. + bool + PrettyPrinter::reduceLeftActiveItems(uint32 rightOffset) + { + uint32 newRightSerialPos = rightSerialPos + rightOffset; + while (activeItems) { + Item *leftItem = &activeItems.front(); + if (itemStack && leftItem == itemStack.front()) { + if (outputPos + newRightSerialPos - leftSerialPos > lineWidth) { + itemStack.pop_front(); + leftItem->lengthKnown = true; + leftItem->totalLength = infiniteLength; + } else if (leftItem->lengthKnown) + itemStack.pop_front(); + } + + if (!leftItem->lengthKnown) + return true; + + activeItems.pop_front(); + try { + uint32 length = leftItem->length; + switch (leftItem->kind) { + case Item::text: + { + outputPos += length; + leftSerialPos += length; + // Exceptions may be thrown below. + char16 *textBegin; + char16 *textEnd; + do { + length -= itemText.pop_front(length, textBegin, + textEnd); + printString(outputFormatter, textBegin, textEnd); + } while (length); + } + break; + + case Item::blockBegin: + case Item::indentBlockBegin: + { + BlockInfo *b = savedBlocks.advance_back(); + b->margin = margin; + b->lastBreak = lastBreak; + b->fits = outputPos + leftItem->totalLength <= lineWidth; + if (leftItem->hasKind(Item::blockBegin)) + margin = outputPos; + else + margin += length; + } + break; + + case Item::blockEnd: + { + BlockInfo &b = savedBlocks.pop_back(); + margin = b.margin; + lastBreak = b.lastBreak; + } + break; + + case Item::indent: + margin += length; + ASSERT(static_cast(margin) >= 0); + break; + + case Item::linearBreak: + // Exceptions may be thrown below, but only after + // updating the PrettyPrinter. + outputBreak(savedBlocks.back().fits, length); + break; + + case Item::fillBreak: + // Exceptions may be thrown below, but only after + // updating the PrettyPrinter. + outputBreak(lastBreak == lineNum && outputPos + + leftItem->totalLength <= lineWidth, length); + break; + } + } catch (...) { + itemPool.destroy(leftItem); + throw; + } + itemPool.destroy(leftItem); + } + return false; + } + + +// A break or end of input is about to be processed. Check whether there are +// any complete blocks or clumps on the itemStack whose lengths we can now +// compute; if so, compute these and pop them off the itemStack. +// The current rightSerialPos must be the beginning of the break or end of input. +// +// This method can't throw exceptions. + void + PrettyPrinter::reduceRightActiveItems() + { + uint32 nUnmatchedBlockEnds = 0; + while (itemStack) { + Item *rightItem = itemStack.pop_back(); + switch (rightItem->kind) { + case Item::blockBegin: + case Item::indentBlockBegin: + if (!nUnmatchedBlockEnds) { + itemStack.fast_push_back(rightItem); + return; + } + rightItem->computeTotalLength(rightSerialPos); + --nUnmatchedBlockEnds; + break; + + case Item::blockEnd: + ++nUnmatchedBlockEnds; + break; + + case Item::linearBreak: + case Item::fillBreak: + rightItem->computeTotalLength(rightSerialPos); + if (!nUnmatchedBlockEnds) + // There can be at most one consecutive break posted on + // the itemStack. + return; + break; + + default: + ASSERT(false); // Other kinds can't be pushed onto the + // itemStack. + } + } + } + + +// Indent the beginning of every new line after this one by offset until the +// corresponding endIndent call. Return an Item to pass to endIndent that will +// end this indentation. This method may throw an exception, in which case the +// PrettyPrinter is left unchanged. + PrettyPrinter::Item & + PrettyPrinter::beginIndent(int32 offset) + { + Item *unindent = new(itemPool) Item(Item::indent, + static_cast(-offset)); + if (activeItems) { + try { + activeItems.push_back(*new(itemPool) Item(Item::indent, + static_cast(offset))); + } catch (...) { + itemPool.destroy(unindent); + throw; + } + } else { + margin += offset; + ASSERT(static_cast(margin) >= 0); + } + return *unindent; + } + + +// End an indent began by beginIndent. i should be the result of a beginIndent. +// This method can't throw exceptions (it's called by the Indent destructor). + void + PrettyPrinter::endIndent(Item &i) + { + if (activeItems) + activeItems.push_back(i); + else { + margin += i.length; + ASSERT(static_cast(margin) >= 0); + itemPool.destroy(&i); + } + } + + +// Begin a logical block. If kind is Item::indentBlockBegin, offset is the +// indent to use for the second and subsequent lines of this block. +// Return an Item to pass to endBlock that will end this block. +// This method may throw an exception, in which case the PrettyPrinter is left +// unchanged. + PrettyPrinter::Item & + PrettyPrinter::beginBlock(Item::Kind kind, int32 offset) + { + uint32 newNNestedBlocks = nNestedBlocks + 1; + savedBlocks.reserve(newNNestedBlocks); + itemStack.reserve_back(1 + newNNestedBlocks); + Item *endItem = new(itemPool) Item(Item::blockEnd); + Item *beginItem; + try { + beginItem = new(itemPool) Item(kind, static_cast(offset), + rightSerialPos); + } catch (...) { + itemPool.destroy(endItem); + throw; + } + // No state modifications before this point. + // No exceptions after this point. + activeItems.push_back(*beginItem); + itemStack.fast_push_back(beginItem); + nNestedBlocks = newNNestedBlocks; + return *endItem; + } + + +// End a logical block began by beginBlock. i should be the result of a +// beginBlock. +// This method can't throw exceptions (it's called by the Block destructor). + void + PrettyPrinter::endBlock(Item &i) + { + activeItems.push_back(i); + itemStack.fast_push_back(&i); + --nNestedBlocks; + } + + +// Write a conditional line break. This kind of a line break can only be +// emitted inside a block. +// A linear line break starts a new line if the containing block cannot be put +// all one one line; otherwise the line break is replaced by nSpaces spaces. +// Typically a block contains several linear breaks; either they all start new +// lines or none of them do. +// Moreover, if a block directly contains a required break then linear breaks +// become required breaks. +// +// A fill line break starts a new line if either the preceding clump or the +// following clump cannot be placed entirely on one line or if the following +// clump would not fit on the current line. A clump is a consecutive sequence +// of strings and nested blocks delimited by either a break or the beginning or +// end of the currently enclosing block. +// +// If this method throws an exception, it leaves the PrettyPrinter in a +// consistent state. + void + PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind) + { + ASSERT(nSpaces <= unlimitedLineWidth && nNestedBlocks); + reduceRightActiveItems(); + itemStack.reserve_back(1 + nNestedBlocks); + // Begin of exception-atomic stack update. Only new(itemPool) can throw + // an exception here, in which case nothing is updated. + Item *i = new(itemPool) Item(kind, nSpaces, rightSerialPos); + activeItems.push_back(*i); + itemStack.fast_push_back(i); + rightSerialPos += nSpaces; + // End of exception-atomic stack update. + reduceLeftActiveItems(0); + } + + +// Write the string between strBegin and strEnd. Any embedded newlines ('\n' +// only) become required line breaks. +// +// If this method throws an exception, it may have partially formatted the +// string but leaves the PrettyPrinter in a consistent state. + void + PrettyPrinter::printStr8(const char *strBegin, const char *strEnd) + { + while (strBegin != strEnd) { + const char *sectionEnd = findValue(strBegin, strEnd, '\n'); + uint32 sectionLength = static_cast(sectionEnd - strBegin); + if (sectionLength) { + if (reduceLeftActiveItems(sectionLength)) { + itemText.reserve_back(sectionLength); + Item &backItem = activeItems.back(); + // Begin of exception-atomic update. Only new(itemPool) + // can throw an exception here, in which case nothing is + // updated. + if (backItem.hasKind(Item::text)) + backItem.length += sectionLength; + else + activeItems.push_back(*new(itemPool) Item(Item::text, + sectionLength)); + rightSerialPos += sectionLength; + itemText.fast_append(reinterpret_cast(strBegin), + reinterpret_cast(sectionEnd)); + // End of exception-atomic update. + } else { + ASSERT(!itemStack && !activeItems && !itemText && + leftSerialPos == rightSerialPos); + outputPos += sectionLength; + printString(outputFormatter, strBegin, sectionEnd); + } + strBegin = sectionEnd; + if (strBegin == strEnd) + break; + } + requiredBreak(); + ++strBegin; + } + } + + +// Write the string between strBegin and strEnd. Any embedded newlines ('\n' +// only) become required line breaks. +// +// If this method throws an exception, it may have partially formatted the +// string but leaves the PrettyPrinter in a consistent state. + void + PrettyPrinter::printStr16(const char16 *strBegin, const char16 *strEnd) + { + while (strBegin != strEnd) { + const char16 *sectionEnd = findValue(strBegin, strEnd, uni::lf); + uint32 sectionLength = static_cast(sectionEnd - strBegin); + if (sectionLength) { + if (reduceLeftActiveItems(sectionLength)) { + itemText.reserve_back(sectionLength); + Item &backItem = activeItems.back(); + // Begin of exception-atomic update. Only new(itemPool) + // can throw an exception here, in which case nothing is + // updated. + if (backItem.hasKind(Item::text)) + backItem.length += sectionLength; + else + activeItems.push_back(*new(itemPool) Item(Item::text, + sectionLength)); + rightSerialPos += sectionLength; + itemText.fast_append(strBegin, sectionEnd); + // End of exception-atomic update. + } else { + ASSERT(!itemStack && !activeItems && !itemText && + leftSerialPos == rightSerialPos); + outputPos += sectionLength; + printString(outputFormatter, strBegin, sectionEnd); + } + strBegin = sectionEnd; + if (strBegin == strEnd) + break; + } + requiredBreak(); + ++strBegin; + } + } + + +// Write a required line break. +// +// If this method throws an exception, it may have emitted partial output but +// leaves the PrettyPrinter in a consistent state. + void + PrettyPrinter::requiredBreak() + { + reduceRightActiveItems(); + reduceLeftActiveItems(infiniteLength); + ASSERT(!itemStack && !activeItems && !itemText && + leftSerialPos == rightSerialPos); + outputBreak(false, 0); + } + + +// If required is true, write a required line break; otherwise write a linear +// line break of the given width. +// +// If this method throws an exception, it may have emitted partial output but +// leaves the PrettyPrinter in a consistent state. + void + PrettyPrinter::linearBreak(uint32 nSpaces, bool required) + { + if (required) + requiredBreak(); + else + linearBreak(nSpaces); + } + + +// Flush any saved output in the PrettyPrinter to the output. Call this just +// before destroying the PrettyPrinter. All Indent and Block objects must have +// been exited already. +// +// If this method throws an exception, it may have emitted partial output but +// leaves the PrettyPrinter in a consistent state. + void + PrettyPrinter::end() + { + ASSERT(!topRegion); + reduceRightActiveItems(); + reduceLeftActiveItems(infiniteLength); + ASSERT(!savedBlocks && !itemStack && !activeItems && !itemText && + rightSerialPos == leftSerialPos && !margin); + } + + +} diff --git a/mozilla/js2/src/formatter.h b/mozilla/js2/src/formatter.h new file mode 100644 index 00000000000..cb7fbdc6a1e --- /dev/null +++ b/mozilla/js2/src/formatter.h @@ -0,0 +1,382 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef formatter_h___ +#define formatter_h___ + +#include +#include + +#include "systemtypes.h" +#include "stlcfg.h" +#include "ds.h" +#include "utilities.h" +#include "strings.h" + +namespace JavaScript +{ +// +// Output +// + +// Print the characters between begin and end to the given file. These +// characters may include nulls. + size_t printChars(FILE *file, const char *begin, const char *end); + +#ifndef XP_MAC_MPW + inline size_t printChars(FILE *file, const char *begin, const char *end) { + ASSERT(end >= begin); + return STD::fwrite(begin, 1, static_cast(end - begin), file); + } +#endif + +// A Formatter is an abstract base class representing a simplified output stream. +// One can print text to a Formatter by using << and the various global +// print... methods below. Formatters accept both char and char16 text and +// convert as appropriate to their actual stream. + class Formatter { + protected: + virtual void printChar8(char ch); + virtual void printChar16(char16 ch); + virtual void printZStr8(const char *str); + virtual void printStr8(const char *strBegin, const char *strEnd) = 0; + virtual void printStr16(const char16 *strBegin, + const char16 *strEnd) = 0; + virtual void printString16(const String &s); + virtual void printVFormat8(const char *format, va_list args); + public: + + Formatter &operator<<(char ch) {printChar8(ch); return *this;} + Formatter &operator<<(char16 ch) {printChar16(ch); return *this;} + Formatter &operator<<(const char *str) {printZStr8(str); return *this;} + Formatter &operator<<(const String &s) {printString16(s); return *this;} + Formatter &operator<<(uint32 i) { + printFormat(*this, "%u", i); + return *this; + } + + friend void printString(Formatter &f, const char *strBegin, + const char *strEnd) { + f.printStr8(strBegin, strEnd); + } + + friend void printString(Formatter &f, const char16 *strBegin, + const char16 *strEnd) { + f.printStr16(strBegin, strEnd); + } + + friend void printFormat(Formatter &f, const char *format, ...) { + va_list args; + va_start(args, format); + f.printVFormat8(format, args); + va_end(args); + } + }; + + void printNum(Formatter &f, uint32 i, int nDigits, char pad, + const char *format); + void printChar(Formatter &f, char ch, int count); + void printChar(Formatter &f, char16 ch, int count); + + inline void printDec(Formatter &f, int32 i, int nDigits = 0, + char pad = ' ') { + printNum(f, (uint32)i, nDigits, pad, "%i"); + } + + inline void printDec(Formatter &f, uint32 i, int nDigits = 0, + char pad = ' ') { + printNum(f, i, nDigits, pad, "%u"); + } + + inline void printHex(Formatter &f, int32 i, int nDigits = 0, + char pad = '0') { + printNum(f, (uint32)i, nDigits, pad, "%X"); + } + + inline void printHex(Formatter &f, uint32 i, int nDigits = 0, + char pad = '0') { + printNum(f, i, nDigits, pad, "%X"); + } + + void printPtr(Formatter &f, void *p); + + + // An AsciiFileFormatter is a Formatter that prints to a standard ASCII + // file or stream. Characters with Unicode values of 256 or higher are + // converted to escape sequences. Selected lower characters can also be + // converted to escape sequences; these are specified by set bits in the + // BitSet passed to the constructor. + class AsciiFileFormatter: public Formatter { + FILE *file; + BitSet<256> filter; // Set of first 256 characters that are to be + // converted to escape sequences + bool filterEmpty; // True if filter passes all 256 characters + public: + static BitSet<256> defaultFilter; // Default value of filter when not + // given in the constructor + + explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0); + + private: + bool filterChar(char ch) {return filter[static_cast(ch)];} + bool filterChar(char16 ch) { + return char16Value(ch) >= 0x100 || filter[char16Value(ch)]; + } + + protected: + void printChar8(char ch); + void printChar16(char16 ch); + void printZStr8(const char *str); + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + }; + + extern AsciiFileFormatter stdOut; + extern AsciiFileFormatter stdErr; + + + // A StringFormatter is a Formatter that prints to a String. + class StringFormatter: public Formatter { + String s; + + public: + const String& getString() { return s; } + void clear() {JavaScript::clear(s);} + protected: + void printChar8(char ch); + void printChar16(char16 ch); + void printZStr8(const char *str); + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + void printString16(const String &str); + }; + + +// +// Formatted Output +// + + class PrettyPrinter: public Formatter { + public: + STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF); + class Region; + class Indent; + class Block; + + private: + STATIC_CONST(uint32, infiniteLength = 0x80000000); + const uint32 lineWidth; // Current maximum desired line width + + struct BlockInfo { + uint32 margin; // Saved margin before this block's beginning + uint32 lastBreak; // Saved lastBreak before this block's beginning + bool fits; // True if this entire block fits on one line + }; + // Variables for the back end that prints to the destination + Formatter &outputFormatter; // Destination formatter on which the + // result should be printed + uint32 outputPos; // Number of characters printed on current + // output line + uint32 lineNum; // Serial number of current line + uint32 lastBreak; // Number of line just after the last + // break that occurred in this block + uint32 margin; // Current left margin in spaces + ArrayBuffer savedBlocks; // Stack of saved information + // about partially printed blocks + + // Variables for the front end that calculates block sizes + struct Item: ListQueueEntry { + enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, + linearBreak, fillBreak}; + + const Kind kind; // The kind of this text sequence + bool lengthKnown; // True if totalLength is known; always true for + // text, blockEnd, and indent Items + uint32 length; // Length of this text sequence, number of spaces + // for this break, or delta for indent or + // indentBlockBegin + uint32 totalLength; // Total length of this block (for blockBegin) + // or length of this break plus following clump + // (for breaks) + // If lengthKnown is false, this is the + // serialPos of this Item instead of a length + bool hasKind(Kind k) const {return kind == k;} + + explicit Item(Kind kind) : + kind(kind), lengthKnown(true) {} + Item(Kind kind, uint32 length) : + kind(kind), lengthKnown(true), length(length) {} + Item(Kind kind, uint32 length, uint32 beginSerialPos): + kind(kind), lengthKnown(false), length(length), + totalLength(beginSerialPos) {} + + void computeTotalLength(uint32 endSerialPos) { + ASSERT(!lengthKnown); + lengthKnown = true; + totalLength = endSerialPos - totalLength; + } + + }; + +#ifdef DEBUG + Region *topRegion; // Most deeply nested Region +#endif + uint32 nNestedBlocks; // Number of nested Blocks + + uint32 leftSerialPos; // The difference rightSerialPos- + uint32 rightSerialPos; // leftSerialPos is always the number of + // characters that would be output by + // printing activeItems if they all fit + // on one line; only the difference + // matters -- the absolute values are + // irrelevant and may wrap around 2^32. + + ArrayQueue itemStack; // Stack of enclosing nested Items + // whose lengths have not yet been + // determined itemStack always has + // room for at least nNestedBlocks + // extra entries so that end Items + // may be added without throwing an + // exception. + + Pool itemPool; // Pool from which to allocate + // activeItems + + ListQueue activeItems; // Queue of items left to be printed + + ArrayQueue itemText; // Text of text items in activeItems, + // in the same order as in activeItems + + public: + static uint32 defaultLineWidth; // Default for lineWidth if not given + // to the constructor + + explicit PrettyPrinter(Formatter &f, + uint32 lineWidth = defaultLineWidth); + private: + PrettyPrinter(const PrettyPrinter&); // No copy constructor + void operator=(const PrettyPrinter&); // No assignment operator + public: + ~PrettyPrinter(); + + private: + void outputBreak(bool sameLine, uint32 nSpaces); + bool reduceLeftActiveItems(uint32 rightOffset); + void reduceRightActiveItems(); + + Item &beginIndent(int32 offset); + void endIndent(Item &i); + + Item &beginBlock(Item::Kind kind, int32 offset); + void endBlock(Item &i); + + void conditionalBreak(uint32 nSpaces, Item::Kind kind); + + protected: + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + public: + + void requiredBreak(); + void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, + Item::linearBreak);} + void linearBreak(uint32 nSpaces, bool required); + void fillBreak(uint32 nSpaces) { + conditionalBreak(nSpaces, Item::fillBreak); + } + + void end(); + + friend class Region; + friend class Indent; + friend class Block; + + class Region { +#ifdef DEBUG + Region *next; // Link to next most deeply nested Region +#endif + protected: + PrettyPrinter &pp; + + Region(PrettyPrinter &pp) : pp(pp) { + DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;); + } + private: + Region(const Region&); // No copy constructor + void operator=(const Region&); // No assignment operator + protected: +#ifdef DEBUG + ~Region() {pp.topRegion = next;} +#endif + }; + + // Use an Indent object to temporarily indent a PrettyPrinter by the + // offset given to the Indent's constructor. The PrettyPrinter's margin + // is set back to its original value when the Indent object is destroyed. + // Using an Indent object is exception-safe; no matter how control + // leaves an Indent scope, the indent is undone. + // Scopes of Indent and Block objects must be properly nested. + class Indent: public Region { + Item &endItem; // The Item returned by beginIndent + public: + Indent(PrettyPrinter &pp, int32 offset) : + Region(pp), endItem(pp.beginIndent(offset)) {} + ~Indent() {pp.endIndent(endItem);} + }; + + // Use a Block object to temporarily enter a PrettyPrinter block. If an + // offset is provided, line breaks inside the block are indented by that + // offset relative to the existing indent; otherwise, line breaks inside + // the block are indented to the current output position. The block + // lasts until the Block object is destroyed. + // Scopes of Indent and Block objects must be properly nested. + class Block: public Region { + Item &endItem; // The Item returned by beginBlock + public: + explicit Block(PrettyPrinter &pp) : + Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {} + Block(PrettyPrinter &pp, int32 offset) : + Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, + offset)) {} + ~Block() {pp.endBlock(endItem);} + }; + }; + + + void escapeString(Formatter &f, const char16 *begin, const char16 *end, + char16 quote); + void quoteString(Formatter &f, const String &s, char16 quote); + +} + +#endif /* formatter_h___ */ diff --git a/mozilla/js2/src/gc_allocator.h b/mozilla/js2/src/gc_allocator.h index 62533999735..e1a5417bc0b 100644 --- a/mozilla/js2/src/gc_allocator.h +++ b/mozilla/js2/src/gc_allocator.h @@ -1,28 +1,43 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 2000 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #ifndef gc_allocator_h #define gc_allocator_h #include -#ifndef _WIN32 // Microsoft VC6 bug: standard identifiers should be in std namespace +// Microsoft VC6 bug: standard identifiers should be in std namespace +#ifndef _WIN32 using std::size_t; using std::ptrdiff_t; #endif @@ -35,129 +50,149 @@ namespace JavaScript { void GC_gcollect(void); typedef void (*GC_finalization_proc) (void* obj, void* client_data); - void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data, - GC_finalization_proc *old_proc, void* *old_client_data); + void GC_register_finalizer(void* obj, GC_finalization_proc proc, + void* client_data, + GC_finalization_proc *old_proc, + void* *old_client_data); } - #if 0 && !defined(XP_MAC) +#if 0 && !defined(XP_MAC) // for platforms where GC doesn't exist yet. inline void* GC_malloc(size_t bytes) { return ::operator new(bytes); } inline void* GC_malloc_atomic(size_t bytes) { return ::operator new(bytes); } inline void GC_free(void* ptr) { operator delete(ptr); } inline void GC_gcollect() {} - inline void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data, - GC_finalization_proc *old_proc, void* *old_client_data) {} - #endif + inline void GC_register_finalizer(void* obj, GC_finalization_proc proc, + void* client_data, + GC_finalization_proc *old_proc, + void* *old_client_data) {} +#endif - /** - * General case: memory for type must be allocated as a conservatively - * scanned block of memory. - */ - template struct gc_traits { - static T* allocate(size_t n) { return static_cast(GC_malloc(n * sizeof(T))); } - }; - - /** - * Specializations for blocks of atomic types: the macro define_atomic_type(_type) - * specializes gc_traits for types that need not be scanned by the - * GC. Implementors are free to define other types as atomic, if they are - * guaranteed not to contain pointers. - */ - #define define_atomic_type(_type) \ - template <> struct gc_traits<_type> { \ - static _type* allocate(size_t n) \ - { \ - return static_cast<_type*>(GC_malloc_atomic(n * sizeof(_type))); \ - } \ - }; - - define_atomic_type(char) - define_atomic_type(unsigned char) - define_atomic_type(short) - define_atomic_type(unsigned short) - define_atomic_type(int) - define_atomic_type(unsigned int) - define_atomic_type(long) - define_atomic_type(unsigned long) - define_atomic_type(float) - define_atomic_type(double) - - #undef define_atomic_type - - /** - * Traits for classes that need to have their destructor called - * when reclaimed by the garbage collector. - */ - template struct gc_traits_finalizable { - static void finalizer(void* obj, void* client_data) - { - T* t = static_cast(obj); - size_t n = reinterpret_cast(client_data); - for (size_t i = 0; i < n; ++i) - t[i].~T(); - } - - static T* allocate(size_t n) - { - T* t = gc_traits::allocate(n); - GC_finalization_proc old_proc; void* old_client_data; - GC_register_finalizer(t, &finalizer, reinterpret_cast(n), &old_proc, &old_client_data); - return t; - } - }; - - /** - * An allocator that can be used to allocate objects in the garbage collected heap. - */ - template > class gc_allocator { - public: - typedef T value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T *pointer; - typedef const T *const_pointer; - typedef T &reference; - typedef const T &const_reference; - - gc_allocator() {} - template gc_allocator(const gc_allocator&) {} - // ~gc_allocator() {} + /** + * General case: memory for type must be allocated as a conservatively + * scanned block of memory. + */ + template struct gc_traits { + static T* allocate(size_t n) { + return static_cast(GC_malloc(n * sizeof(T))); + } + }; + + /** + * Specializations for blocks of atomic types: the macro define_atomic_type(_type) + * specializes gc_traits for types that need not be scanned by the + * GC. Implementors are free to define other types as atomic, if they are + * guaranteed not to contain pointers. + */ +#define define_atomic_type(_type) \ + template <> struct gc_traits<_type> { \ + static _type* allocate(size_t n) \ + { \ + return static_cast<_type*>(GC_malloc_atomic(n * sizeof(_type))); \ + } \ + }; + + define_atomic_type(char) + define_atomic_type(unsigned char) + define_atomic_type(short) + define_atomic_type(unsigned short) + define_atomic_type(int) + define_atomic_type(unsigned int) + define_atomic_type(long) + define_atomic_type(unsigned long) + define_atomic_type(float) + define_atomic_type(double) + + #undef define_atomic_type + + /** + * Traits for classes that need to have their destructor called + * when reclaimed by the garbage collector. + */ + template struct gc_traits_finalizable { + static void finalizer(void* obj, void* client_data) + { + T* t = static_cast(obj); + size_t n = reinterpret_cast(client_data); + for (size_t i = 0; i < n; ++i) + t[i].~T(); + } + + static T* allocate(size_t n) + { + T* t = gc_traits::allocate(n); + GC_finalization_proc old_proc; void* old_client_data; + GC_register_finalizer(t, &finalizer, reinterpret_cast(n), + &old_proc, &old_client_data); + return t; + } + }; + + /** + * An allocator that can be used to allocate objects in the garbage + * collected heap. + */ + template > class gc_allocator { + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + + gc_allocator() {} + template + gc_allocator(const gc_allocator&) {} + // ~gc_allocator() {} - static pointer address(reference r) { return &r; } - static const_pointer address(const_reference r) { return &r; } - - static pointer allocate(size_type n, const void* /* hint */ = 0) { return traits::allocate(n); } - static void deallocate(pointer, size_type) {} - - static void construct(pointer p, const T &val) { new(p) T(val);} - static void destroy(pointer p) { p->~T(); } - + static pointer address(reference r) { return &r; } + static const_pointer address(const_reference r) { return &r; } + + static pointer allocate(size_type n, const void* /* hint */ = 0) { + return traits::allocate(n); + } + static void deallocate(pointer, size_type) {} + + static void construct(pointer p, const T &val) { new(p) T(val);} + static void destroy(pointer p) { p->~T(); } + #if defined(__GNUC__) || defined(_WIN32) static size_type max_size() { return size_type(-1) / sizeof(T); } #else - static size_type max_size() { return std::numeric_limits::max() / sizeof(T); } + static size_type max_size() { + return std::numeric_limits::max() / sizeof(T); + } #endif - template struct rebind { typedef gc_allocator other; }; + template struct rebind { typedef gc_allocator other; }; #ifdef _WIN32 - // raw byte allocator used on some platforms (grrr). - typedef char _Char[1]; - static char* _Charalloc(size_type n) { return (char*) rebind<_Char>::other::allocate(n); } + // raw byte allocator used on some platforms (grrr). + typedef char _Char[1]; + static char* _Charalloc(size_type n) { + return (char*) rebind<_Char>::other::allocate(n); + } - // funky operator required for calling basic_string constructor (grrr). - template int operator==(const gc_allocator&) { return 0; } + /** + * funky operator required for calling basic_string constructor + * (grrr). + */ + template + int operator==(const gc_allocator&) { return 0; } #endif - // void* deallocate used on some platforms (grrr). - static void deallocate(void*, size_type) {} + // void* deallocate used on some platforms (grrr). + static void deallocate(void*, size_type) {} - static void collect() { GC_gcollect(); } - }; + static void collect() { GC_gcollect(); } + }; /** - * Generic base class for objects allocated using a gc_allocator. How they are allocated - * can be controlled by specializing gc_traits for the specific class. + * Generic base class for objects allocated using a gc_allocator. How they + * are allocated can be controlled by specializing gc_traits for the + * specific class. */ template class gc_object { public: @@ -166,7 +201,8 @@ namespace JavaScript { }; /** - * Simpler base class for classes that have no need to specialize allocation behavior. + * Simpler base class for classes that have no need to specialize allocation + * behavior. */ class gc_base { public: diff --git a/mozilla/js2/src/gc_container.h b/mozilla/js2/src/gc_container.h index 9bb5b548f26..ca8a91ca00a 100644 --- a/mozilla/js2/src/gc_container.h +++ b/mozilla/js2/src/gc_container.h @@ -1,21 +1,35 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 2000 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #ifndef gc_container_h #define gc_container_h @@ -39,33 +53,33 @@ #endif namespace JavaScript { - /** - * Rebind some of the basic container types to use a GC_allocator. - * What I really want is something more general, something like: - * template class gc_rebind { - * typedef typename Container > other; - * }; - * But I can't figure out how to do that with C++ templates. - */ - template struct gc_container { - typedef typename LIST > list; - typedef typename VECTOR > vector; - typedef typename STRING, gc_allocator > string; - }; + /** + * Rebind some of the basic container types to use a GC_allocator. + * What I really want is something more general, something like: + * template class gc_rebind { + * typedef typename Container > other; + * }; + * But I can't figure out how to do that with C++ templates. + */ + template struct gc_container { + typedef typename LIST > list; + typedef typename VECTOR > vector; + typedef typename STRING, gc_allocator > string; + }; - /** - * But, it's pretty easy to do with macros: - */ - #define GC_CONTAINER(container, type) container > - - /* - // this gives an "unimplemented C++ feature" error using CWPro5. - // maybe someday. - template typename Container, typename T> - struct gc_rebind { - typedef typename Container > container; - }; - */ + /** + * But, it's pretty easy to do with macros: + */ + #define GC_CONTAINER(container, type) container > + + /* + // this gives an "unimplemented C++ feature" error using CWPro5. + // maybe someday. + template typename Container, typename T> + struct gc_rebind { + typedef typename Container > container; + }; + */ } #endif /* gc_container_h */ diff --git a/mozilla/js2/src/hash.cpp b/mozilla/js2/src/hash.cpp index 31d721b9843..8b27b6f01b4 100644 --- a/mozilla/js2/src/hash.cpp +++ b/mozilla/js2/src/hash.cpp @@ -1,173 +1,190 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #include "hash.h" #include -namespace JS = JavaScript; - +namespace JavaScript +{ // // Hash Codes // - // General-purpose null-terminated C string hash function -JS::HashNumber JS::hashString(const char *s) -{ - HashNumber h = 0; - uchar ch; - - while ((ch = (uchar)*s++) != 0) - h = (h >> 28) ^ (h << 4) ^ ch; - return h; -} - + HashNumber + hashString(const char *s) + { + HashNumber h = 0; + uchar ch; + + while ((ch = (uchar)*s++) != 0) + h = (h >> 28) ^ (h << 4) ^ ch; + return h; + } // General-purpose String hash function -JS::HashNumber JS::hashString(const String &s) -{ - HashNumber h = 0; - String::const_iterator p = s.begin(); - String::size_type n = s.size(); - - if (n < 16) - // Hash every character in a short string. - while (n--) - h = (h >> 28) ^ (h << 4) ^ *p++; - else - // Sample a la java.lang.String.hash(). - for (String::size_type m = n / 8; n >= m; p += m, n -= m) - h = (h >> 28) ^ (h << 4) ^ *p; - return h; -} - + HashNumber + hashString(const String &s) + { + HashNumber h = 0; + String::const_iterator p = s.begin(); + String::size_type n = s.size(); + + if (n < 16) + // Hash every character in a short string. + while (n--) + h = (h >> 28) ^ (h << 4) ^ *p++; + else + // Sample a la java.lang.String.hash(). + for (String::size_type m = n / 8; n >= m; p += m, n -= m) + h = (h >> 28) ^ (h << 4) ^ *p; + return h; + } // // Hash Tables // + const uint minLgNBuckets = 4; -const uint minLgNBuckets = 4; - - -JS::GenericHashTableIterator::GenericHashTableIterator(GenericHashTable &ht): - ht(ht), entry(0), nextBucket(ht.buckets) -{ - DEBUG_ONLY(++ht.nReferences); - operator++(); -} + GenericHashTableIterator::GenericHashTableIterator(GenericHashTable &ht): + ht(ht), entry(0), nextBucket(ht.buckets) + { + DEBUG_ONLY(++ht.nReferences); + operator++(); + } -JS::GenericHashTableIterator & -JS::GenericHashTableIterator::operator++() -{ - GenericHashEntry *e = entry; + GenericHashTableIterator & + GenericHashTableIterator::operator++() + { + GenericHashEntry *e = entry; - if (e) { - backpointer = &e->next; - e = e->next; - } - if (!e) { - GenericHashEntry **const bucketsEnd = ht.bucketsEnd; - GenericHashEntry **bucket = nextBucket; + if (e) { + backpointer = &e->next; + e = e->next; + } + if (!e) { + GenericHashEntry **const bucketsEnd = ht.bucketsEnd; + GenericHashEntry **bucket = nextBucket; - while (bucket != bucketsEnd) { - e = *bucket++; - if (e) { - backpointer = bucket-1; - break; - } - } - nextBucket = bucket; - } - entry = e; - return *this; -} + while (bucket != bucketsEnd) { + e = *bucket++; + if (e) { + backpointer = bucket-1; + break; + } + } + nextBucket = bucket; + } + entry = e; + return *this; + } + + + GenericHashTable::GenericHashTable(uint32 nEntriesDefault) : + nEntries(0) + { + DEBUG_ONLY(nReferences = 0); + uint lgNBuckets = ceilingLog2(nEntriesDefault); + if (lgNBuckets < minLgNBuckets) + lgNBuckets = minLgNBuckets; + defaultLgNBuckets = lgNBuckets; -JS::GenericHashTable::GenericHashTable(uint32 nEntriesDefault): - nEntries(0) -{ - DEBUG_ONLY(nReferences = 0); + recomputeMinMaxNEntries(lgNBuckets); + uint32 nBuckets = JS_BIT(lgNBuckets); + buckets = new GenericHashEntry*[nBuckets]; + // No exceptions after this point unless buckets is deleted. - uint lgNBuckets = ceilingLog2(nEntriesDefault); - if (lgNBuckets < minLgNBuckets) - lgNBuckets = minLgNBuckets; - defaultLgNBuckets = lgNBuckets; - - recomputeMinMaxNEntries(lgNBuckets); - uint32 nBuckets = JS_BIT(lgNBuckets); - buckets = new GenericHashEntry*[nBuckets]; - // No exceptions after this point unless buckets is deleted. - - bucketsEnd = buckets + nBuckets; - zero(buckets, bucketsEnd); -} + bucketsEnd = buckets + nBuckets; + zero(buckets, bucketsEnd); + } // Initialize shift, minNEntries, and maxNEntries based on the lg2 of the // number of buckets. -void JS::GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets) -{ - uint32 nBuckets = JS_BIT(lgNBuckets); - shift = 32 - lgNBuckets; - maxNEntries = nBuckets; // Maximum ratio is 100% - minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3); // Minimum ratio is 37.5% -} + void + GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets) + { + uint32 nBuckets = JS_BIT(lgNBuckets); + shift = 32 - lgNBuckets; + maxNEntries = nBuckets; // Maximum ratio is 100% + // Minimum ratio is 37.5% + minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3); + } // Rehash the table. This method cannot throw out-of-memory exceptions, so it is // safe to call from a destructor. -void JS::GenericHashTable::rehash() -{ - uint32 newLgNBuckets = ceilingLog2(nEntries); - if (newLgNBuckets < defaultLgNBuckets) - newLgNBuckets = defaultLgNBuckets; - uint32 newNBuckets = JS_BIT(newLgNBuckets); - try { - GenericHashEntry **newBuckets = new GenericHashEntry*[newNBuckets]; - // No exceptions after this point. + void + GenericHashTable::rehash() + { + uint32 newLgNBuckets = ceilingLog2(nEntries); + if (newLgNBuckets < defaultLgNBuckets) + newLgNBuckets = defaultLgNBuckets; + uint32 newNBuckets = JS_BIT(newLgNBuckets); + try { + GenericHashEntry **newBuckets = new GenericHashEntry*[newNBuckets]; + // No exceptions after this point. - GenericHashEntry **newBucketsEnd = newBuckets + newNBuckets; - zero(newBuckets, newBucketsEnd); - recomputeMinMaxNEntries(newLgNBuckets); - GenericHashEntry **be = bucketsEnd; - for (GenericHashEntry **b = buckets; b != be; b++) { - GenericHashEntry *e = *b; - while (e) { - GenericHashEntry *next = e->next; - // Place e in the new set of buckets. - GenericHashEntry **nb = newBuckets + (e->keyHash*goldenRatio >> shift); - e->next = *nb; - *nb = e; - e = next; - } - } - delete[] buckets; - buckets = newBuckets; - bucketsEnd = newBucketsEnd; - } catch (std::bad_alloc) { - // Out of memory. Ignore the error and just relax the resizing boundaries. - if (buckets + JS_BIT(newLgNBuckets) > bucketsEnd) - maxNEntries >>= 1; - else - minNEntries <<= 1; - } + GenericHashEntry **newBucketsEnd = newBuckets + newNBuckets; + zero(newBuckets, newBucketsEnd); + recomputeMinMaxNEntries(newLgNBuckets); + GenericHashEntry **be = bucketsEnd; + for (GenericHashEntry **b = buckets; b != be; b++) { + GenericHashEntry *e = *b; + while (e) { + GenericHashEntry *next = e->next; + // Place e in the new set of buckets. + GenericHashEntry **nb = + newBuckets + (e->keyHash*goldenRatio >> shift); + e->next = *nb; + *nb = e; + e = next; + } + } + delete[] buckets; + buckets = newBuckets; + bucketsEnd = newBucketsEnd; + } catch (std::bad_alloc) { + // Out of memory. Ignore the error and just relax the resizing + // boundaries. + if (buckets + JS_BIT(newLgNBuckets) > bucketsEnd) + maxNEntries >>= 1; + else + minNEntries <<= 1; + } + } } diff --git a/mozilla/js2/src/hash.h b/mozilla/js2/src/hash.h index f2ae54dc7dc..d398c7c5d02 100644 --- a/mozilla/js2/src/hash.h +++ b/mozilla/js2/src/hash.h @@ -1,372 +1,421 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#ifndef hash_h -#define hash_h +#ifndef hash_h___ +#define hash_h___ +#include "systemtypes.h" #include "utilities.h" +#include "strings.h" +#include "algo.h" namespace JavaScript { - // // Hash Codes // - typedef uint32 HashNumber; + typedef uint32 HashNumber; - HashNumber hashString(const char *s); - HashNumber hashString(const String &s); + HashNumber hashString(const char *s); + HashNumber hashString(const String &s); + + template + struct Hash { + HashNumber operator()(Key key) const; + }; + + template + inline HashNumber Hash::operator()(Key key) const + { + return hashString(key); + } - template - struct Hash { - HashNumber operator()(Key key) const; - }; - - template - inline HashNumber Hash::operator()(Key key) const - { - return hashString(key); - } - - - const HashNumber goldenRatio = 0x9E3779B9U; - + const HashNumber goldenRatio = 0x9E3779B9U; // // Private // - // Base class for user-defined hash entries. - // private - class GenericHashEntry { - public: - GenericHashEntry *next; // Link to next entry in the same bucket - const HashNumber keyHash; // This entry's hash value + // Base class for user-defined hash entries. + // private + class GenericHashEntry { + public: + GenericHashEntry *next; // Link to next entry in the same bucket + const HashNumber keyHash; // This entry's hash value - protected: - explicit GenericHashEntry(HashNumber keyHash): next(0), keyHash(keyHash) {} + protected: + explicit GenericHashEntry(HashNumber keyHash) : + next(0), keyHash(keyHash) {} - friend class GenericHashTable; - }; + friend class GenericHashTable; + }; - // private - class GenericHashTableIterator; - class GenericHashTable { - protected: - GenericHashEntry **buckets; // Vector of hash buckets - GenericHashEntry **bucketsEnd; // Pointer past end of vector of hash buckets - uint defaultLgNBuckets; // lg2 of minimum number of buckets for which to size the table - uint32 nEntries; // Number of entries in table - uint32 minNEntries; // Minimum number of entries without rehashing - uint32 maxNEntries; // Maximum number of entries without rehashing - uint32 shift; // 32 - lg2(number of buckets) - #ifdef DEBUG - public: - uint32 nReferences; // Number of iterators and references currently pointing to this hash table - #endif + // private + class GenericHashTableIterator; + class GenericHashTable { + protected: + GenericHashEntry **buckets; // Vector of hash buckets + GenericHashEntry **bucketsEnd; // Pointer past end of vector of hash + // buckets + uint defaultLgNBuckets; // lg2 of minimum number of buckets for + // which to size the table + uint32 nEntries; // Number of entries in table + uint32 minNEntries; // Minimum number of entries without + // rehashing + uint32 maxNEntries; // Maximum number of entries without + // rehashing + uint32 shift; // 32 - lg2(number of buckets) +#ifdef DEBUG + public: + uint32 nReferences; // Number of iterators and references + // currently pointing to this hash table +#endif - public: - explicit GenericHashTable(uint32 nEntriesDefault); - ~GenericHashTable() { - #ifndef _WIN32 - ASSERT(nReferences == 0); - #endif - delete[] buckets; - } + public: + explicit GenericHashTable(uint32 nEntriesDefault); + ~GenericHashTable() { +#ifndef _WIN32 + ASSERT(nReferences == 0); +#endif + delete[] buckets; + } - void recomputeMinMaxNEntries(uint lgNBuckets); - void rehash(); - void maybeGrow() {if (nEntries > maxNEntries) rehash();} - void maybeShrink() {if (nEntries < minNEntries) rehash();} - - friend class GenericHashTableIterator; + void recomputeMinMaxNEntries(uint lgNBuckets); + void rehash(); + void maybeGrow() {if (nEntries > maxNEntries) rehash();} + void maybeShrink() {if (nEntries < minNEntries) rehash();} + + friend class GenericHashTableIterator; - typedef GenericHashTableIterator Iterator; - }; + typedef GenericHashTableIterator Iterator; + }; - // This ought to be GenericHashTable::Iterator, but this doesn't work due to a - // Microsoft VC6 bug. - class GenericHashTableIterator { - protected: - GenericHashTable &ht; // Hash table being iterated - GenericHashEntry *entry; // Current entry; nil if done - GenericHashEntry **backpointer; // Pointer to pointer to current entry - GenericHashEntry **nextBucket; // Next bucket; pointer past end of vector of hash buckets if done - public: - explicit GenericHashTableIterator(GenericHashTable &ht); - ~GenericHashTableIterator() {ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);} + // This ought to be GenericHashTable::Iterator, but this doesn't work + // due to a Microsoft VC6 bug. + class GenericHashTableIterator { + protected: + GenericHashTable &ht; // Hash table being iterated + GenericHashEntry *entry; // Current entry; nil if done + GenericHashEntry **backpointer; // Pointer to pointer to current entry + GenericHashEntry **nextBucket; // Next bucket; pointer past end of + // vector of hash buckets if done + public: + explicit GenericHashTableIterator(GenericHashTable &ht); + ~GenericHashTableIterator() { + ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences); + } - operator bool() const {return entry != 0;} // Return true if there are entries left. - GenericHashTableIterator &operator++(); - }; + // Return true if there are entries left. + operator bool() const {return entry != 0;} + + GenericHashTableIterator &operator++(); + }; // // Hash Tables // - template > - class HashTable: private GenericHashTable { - H hasher; // Hash function + template > + class HashTable: private GenericHashTable { + H hasher; // Hash function - struct Entry: public GenericHashEntry { - Data data; - - Entry(HashNumber keyHash, Key key): GenericHashEntry(keyHash), data(key) {} - template - Entry(HashNumber keyHash, Key key, Value value): GenericHashEntry(keyHash), data(key, value) {} - }; + struct Entry: public GenericHashEntry { + Data data; + + Entry(HashNumber keyHash, Key key) : + GenericHashEntry(keyHash), data(key) {} + template + Entry(HashNumber keyHash, Key key, Value value) : + GenericHashEntry(keyHash), data(key, value) {} + }; - public: - class Reference { -#ifdef _WIN32 // Microsoft VC6 bug: friend declarations to inner classes don't work - public: + public: + class Reference { +#ifdef _WIN32 + // Microsoft VC6 bug: friend declarations to inner classes don't work + public: +#endif + Entry *entry; // Current entry; nil if done + GenericHashEntry **backpointer; // Pointer to pointer to current + // entry + const HashNumber keyHash; // This entry's key's hash value +#ifdef DEBUG + GenericHashTable *ht; // Hash table to which this + // Reference points #endif - Entry *entry; // Current entry; nil if done - GenericHashEntry **backpointer; // Pointer to pointer to current entry - const HashNumber keyHash; // This entry's key's hash value - #ifdef DEBUG - GenericHashTable *ht; // Hash table to which this Reference points - #endif - public: + public: #ifndef _WIN32 - Reference(HashTable &ht, Key key); // Search for an entry with the given key. -#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class - Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) { - #ifdef DEBUG - Reference::ht = &ht; - ++ht.nReferences; - #endif - HashNumber kh = keyHash; - HashNumber h = kh*goldenRatio >> ht.shift; - GenericHashEntry **bp = ht.buckets + h; - Entry *e; - - while ((e = static_cast(*bp)) != 0 && !(e->keyHash == kh && e->data == key)) - bp = &e->next; - entry = e; - backpointer = bp; - } + Reference(HashTable &ht, Key key); // Search for an entry with the + // given key. +#else + // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside + // the class + Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) { +#ifdef DEBUG + Reference::ht = &ht; + ++ht.nReferences; #endif - private: - Reference(const Reference&); // No copy constructor - void operator=(const Reference&); // No assignment operator - public: - #if defined(DEBUG) && !defined(_WIN32) - ~Reference() {if (ht) --ht->nReferences;} - #endif - - operator bool() const {return entry != 0;} // Return true if an entry was found. - Data &operator*() const {ASSERT(entry); return entry->data;} // Return the data of the entry that was found. - - friend class HashTable; - }; + HashNumber kh = keyHash; + HashNumber h = kh*goldenRatio >> ht.shift; + GenericHashEntry **bp = ht.buckets + h; + Entry *e; - class Iterator: public GenericHashTableIterator { - public: - explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {} - private: - Iterator(const Iterator&); // No copy constructor - void operator=(const Iterator&); // No assignment operator - public: + while ((e = static_cast(*bp)) != 0 && + !(e->keyHash == kh && e->data == key)) + bp = &e->next; + entry = e; + backpointer = bp; + } +#endif + private: + Reference(const Reference&); // No copy constructor + void operator=(const Reference&); // No assignment operator + public: +#if defined(DEBUG) && !defined(_WIN32) + ~Reference() {if (ht) --ht->nReferences;} +#endif - // Go to next entry. - Iterator &operator++() {return *static_cast(&GenericHashTableIterator::operator++());} - Data &operator*() const {ASSERT(entry); return static_cast(entry)->data;} // Return current entry's data. - void erase(); - }; + // Return true if an entry was found. + operator bool() const {return entry != 0;} + // Return the data of the entry that was found. + Data &operator*() const {ASSERT(entry); return entry->data;} + + friend class HashTable; + }; - HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()): GenericHashTable(nEntriesDefault), hasher(hasher) {} - ~HashTable(); + class Iterator: public GenericHashTableIterator { + public: + explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {} + private: + Iterator(const Iterator&); // No copy constructor + void operator=(const Iterator&); // No assignment operator + public: - template Data &insert(Reference &r, Key key, Value value); - Data &insert(Reference &r, Key key); - Data &insert(Key key); - void erase(Reference &r); - void erase(Key key); - Data *operator[](Key key); - - friend class Reference; - friend class Iterator; + // Go to next entry. + Iterator &operator++() { + return *static_cast(&GenericHashTableIterator::operator++()); + } + Data &operator*() const { + // Return current entry's data. + ASSERT(entry); + return static_cast(entry)->data; + } + + void erase(); + + }; + + HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()) : + GenericHashTable(nEntriesDefault), hasher(hasher) {} + ~HashTable(); + + template Data &insert(Reference &r, Key key, Value value); + Data &insert(Reference &r, Key key); + Data &insert(Key key); + void erase(Reference &r); + void erase(Key key); + Data *operator[](Key key); + + friend class Reference; + friend class Iterator; #ifndef _WIN32 - template Data &insert(Key key, Value value); -#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class - template Data &insert(Key key, Value value) { - Reference r(*this, key); - if (r) - return *r = value; - else - return insert(r, key, value); - } + template Data &insert(Key key, Value value); +#else + // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the + // class + template Data &insert(Key key, Value value) { + Reference r(*this, key); + if (r) + return *r = value; + else + return insert(r, key, value); + } #endif - }; + }; // // Implementation // - template - HashTable::~HashTable() - { - GenericHashEntry **be = bucketsEnd; - for (GenericHashEntry **b = buckets; b != be; b++) { - Entry *e = static_cast(*b); - while (e) { - Entry *next = static_cast(e->next); - delete e; - e = next; - } - } - } + template + HashTable::~HashTable() + { + GenericHashEntry **be = bucketsEnd; + for (GenericHashEntry **b = buckets; b != be; b++) { + Entry *e = static_cast(*b); + while (e) { + Entry *next = static_cast(e->next); + delete e; + e = next; + } + } + } #ifndef _WIN32 - template - HashTable::Reference::Reference(HashTable &ht, Key key): - keyHash(ht.hasher(key)) - { - #ifdef DEBUG - Reference::ht = &ht; - ++ht.nReferences; - #endif - HashNumber kh = keyHash; - HashNumber h = kh*goldenRatio >> ht.shift; - GenericHashEntry **bp = ht.buckets + h; - Entry *e; + template + HashTable::Reference::Reference(HashTable &ht, Key key): + keyHash(ht.hasher(key)) + { +#ifdef DEBUG + Reference::ht = &ht; + ++ht.nReferences; +#endif + HashNumber kh = keyHash; + HashNumber h = kh*goldenRatio >> ht.shift; + GenericHashEntry **bp = ht.buckets + h; + Entry *e; - while ((e = static_cast(*bp)) != 0 && !(e->keyHash == kh && e->data == key)) - bp = &e->next; - entry = e; - backpointer = bp; - } + while ((e = static_cast(*bp)) != 0 && + !(e->keyHash == kh && e->data == key)) + bp = &e->next; + entry = e; + backpointer = bp; + } - // Insert the given key/value pair into the hash table. Reference must - // be the result of an unsuccessful search for that key in the table. - // The reference is not valid after this method is called. - // Return a reference to the new entry's value. - template template - inline Data &HashTable::insert(Reference &r, Key key, Value value) - { - ASSERT(r.ht == this && !r.entry); - Entry *e = new Entry(r.keyHash, key, value); - *r.backpointer = e; - ++nEntries; - maybeGrow(); - #ifdef DEBUG - --r.ht->nReferences; - r.ht = 0; - #endif - return e->data; - } + // Insert the given key/value pair into the hash table. Reference must + // be the result of an unsuccessful search for that key in the table. + // The reference is not valid after this method is called. + // Return a reference to the new entry's value. + template template + inline Data &HashTable::insert(Reference &r, Key key, Value value) + { + ASSERT(r.ht == this && !r.entry); + Entry *e = new Entry(r.keyHash, key, value); + *r.backpointer = e; + ++nEntries; + maybeGrow(); +#ifdef DEBUG + --r.ht->nReferences; + r.ht = 0; +#endif + return e->data; + } #endif - // Same as above but without a Value argument. - template - inline Data &HashTable::insert(Reference &r, Key key) - { - ASSERT(r.ht == this && !r.entry); - Entry *e = new Entry(r.keyHash, key); - *r.backpointer = e; - ++nEntries; - maybeGrow(); - #ifdef DEBUG - --r.ht->nReferences; - r.ht = 0; - #endif - return e->data; - } + // Same as above but without a Value argument. + template + inline Data &HashTable::insert(Reference &r, Key key) + { + ASSERT(r.ht == this && !r.entry); + Entry *e = new Entry(r.keyHash, key); + *r.backpointer = e; + ++nEntries; + maybeGrow(); +#ifdef DEBUG + --r.ht->nReferences; + r.ht = 0; +#endif + return e->data; + } - // Insert the given key/value pair into the hash table. If an entry with a - // matching key already exists, replace that entry's value. - // Return a reference to the new entry's value. -#ifndef _WIN32 // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class - template template - Data &HashTable::insert(Key key, Value value) - { - Reference r(*this, key); - if (r) - return *r = value; - else - return insert(r, key, value); - } + // Insert the given key/value pair into the hash table. If an entry with a + // matching key already exists, replace that entry's value. + // Return a reference to the new entry's value. +#ifndef _WIN32 + // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class + template template + Data &HashTable::insert(Key key, Value value) + { + Reference r(*this, key); + if (r) + return *r = value; + else + return insert(r, key, value); + } #endif - // Same as above but without a Value argument. - template - Data &HashTable::insert(Key key) - { - Reference r(*this, key); - if (r) - return *r; - else - return insert(r, key); - } + // Same as above but without a Value argument. + template + Data &HashTable::insert(Key key) + { + Reference r(*this, key); + if (r) + return *r; + else + return insert(r, key); + } - // Reference r must point to an existing entry. Delete that entry. - // The reference is not valid after this method is called. - template - inline void HashTable::erase(Reference &r) - { - Entry *e = r.entry; - ASSERT(r.ht == this && e); - *r.backpointer = e->next; - --nEntries; - delete e; - #ifdef DEBUG - --r.ht->nReferences; - r.ht = 0; - #endif - maybeShrink(); - } + // Reference r must point to an existing entry. Delete that entry. + // The reference is not valid after this method is called. + template + inline void HashTable::erase(Reference &r) + { + Entry *e = r.entry; + ASSERT(r.ht == this && e); + *r.backpointer = e->next; + --nEntries; + delete e; +#ifdef DEBUG + --r.ht->nReferences; + r.ht = 0; +#endif + maybeShrink(); + } - // Remove the hash table entry, if any, matching the given key. - template - void HashTable::erase(Key key) - { - Reference r(*this, key); - if (r) - erase(r); - } + // Remove the hash table entry, if any, matching the given key. + template + void HashTable::erase(Key key) + { + Reference r(*this, key); + if (r) + erase(r); + } - // Return a pointer to the value of the hash table entry matching the given key. - // Return nil if no entry matches. - template - Data *HashTable::operator[](Key key) - { - Reference r(*this, key); - if (r) - return &*r; - else - return 0; - } + // Return a pointer to the value of the hash table entry matching the given + // key. Return nil if no entry matches. + template + Data *HashTable::operator[](Key key) + { + Reference r(*this, key); + if (r) + return &*r; + else + return 0; + } } diff --git a/mozilla/js2/src/ica-exception.cpp b/mozilla/js2/src/ica-exception.cpp new file mode 100644 index 00000000000..7c5a7d08c01 --- /dev/null +++ b/mozilla/js2/src/ica-exception.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include "exception.h" + +namespace JavaScript { + + extern const char* exception_types[]; + extern const char* exception_msgs[]; + + void + JSException::toString8 (string8 &rval) + { + rval = string8(exception_types[mType]) + " Exception: " + + string8(exception_msgs[mID]); + if (mSource.size() != 0) + rval += " in " + mSource; + } + +} + diff --git a/mozilla/js2/src/ica-exception.h b/mozilla/js2/src/ica-exception.h new file mode 100644 index 00000000000..4fed93e905c --- /dev/null +++ b/mozilla/js2/src/ica-exception.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef exception_h___ +#define exception_h___ +#include "utilities.h" + +namespace JavaScript { + + enum ExceptionType { + etUnknown = 0, + etLexer, + etParser, + etRuntime, + etCount + }; + + enum ExceptionID { + eidExpectBool = 0, + eidExpectDouble, + eidExpectInt32, + eidExpectUInt32, + eidExpectRegister, + eidExpectArgList, + eidExpectColon, + eidExpectCloseParen, + eidExpectBinaryOp, + eidExpectString, + eidExpectLabel, + eidExpectComma, + eidExpectNewline, + eidExpectIdentifier, + eidDuplicateLabel, + eidUnknownICode, + eidUnknownBinaryOp, + eidUnterminatedString, + eidCount + }; + + class JSException { + public: + JSException (ExceptionID ID, string8_citer pos = 0, + string8 source = "", ExceptionType type = etUnknown) + : mID(ID), mType(type), mPos(pos), mSource(source) {} + ExceptionID mID; + ExceptionType mType; + string8_citer mPos; + string8 mSource; + + public: + void toString8(string8 &rval); + /* + private: + JSException(const JSException&); + */ + + }; + + class JSLexException : public JSException { + public: + JSLexException (ExceptionID ID, string8_citer pos = 0, + string8 source = "") : + JSException(ID, pos, source, etLexer) {} + /* + private: + JSLexException (const JSLexException&); + */ + }; + + class JSParseException : public JSException { + public: + JSParseException (ExceptionID ID, string8_citer pos = 0, + string8 source = "") : + JSException(ID, pos, source, etParser) {} + /* + private: + JSParseException (const JSParseException&); + */ + }; + +} + +#endif /* exception_h___ */ + + diff --git a/mozilla/js2/src/kitchensink.cpp b/mozilla/js2/src/kitchensink.cpp new file mode 100644 index 00000000000..7c1f10a358e --- /dev/null +++ b/mozilla/js2/src/kitchensink.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include +#include +#include "utilities.h" + +#ifdef WIN32 + #include +#endif + +#ifdef XP_MAC + #include + #include +#endif + +namespace JS = JavaScript; + + + + +// +// Input +// + + + +// +// Output +// + + + +// +// Static Initializers +// + + +#ifndef _WIN32 +static void jsNewHandler() +{ + std::bad_alloc outOfMemory; + throw outOfMemory; +} + + +struct InitUtilities +{ + InitUtilities() {std::set_new_handler(&jsNewHandler);} +}; +#else +#include +static int jsNewHandler(size_t) +{ + std::bad_alloc outOfMemory; + throw outOfMemory; +} + + +struct InitUtilities +{ + InitUtilities() {_set_new_handler(&jsNewHandler);} +}; +#endif +InitUtilities initUtilities; diff --git a/mozilla/js2/src/kitchensink.h b/mozilla/js2/src/kitchensink.h new file mode 100644 index 00000000000..18e9df0c25a --- /dev/null +++ b/mozilla/js2/src/kitchensink.h @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef kitchensink_h___ +#define kitchensink_h___ + +#include +#include +#include +#include +#include +#include +#include + +#include "stlcfg.h" +#include "systemtypes.h" +#include "strings.h" +#include "mem.h" + + +namespace JavaScript { +// +// Numerics +// + + template N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;} + template N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;} + + +// +// Alignment +// + + template + struct AlignmentHelper { + char ch; + T t; + }; + #define ALIGNMENT_OF(T) offsetof(JavaScript::AlignmentHelper, t) + + + + // Assign zero to n elements starting at first. + // This is equivalent ot fill_n(first, n, 0) but may be more efficient. + template + inline void zero_n(ForwardIterator first, Size n) + { + while (n) { + *first = 0; + ++first; + --n; + } + } + +// +// Linked Lists +// + + // In some cases it is desirable to manipulate ordinary C-style linked lists as though + // they were STL-like sequences. These classes define STL forward iterators that walk + // through singly-linked lists of objects threaded through fields named 'next'. The type + // parameter E must be a class that has a member named 'next' whose type is E* or const E*. + + template + class ListIterator: public std::iterator { + E *element; + + public: + ListIterator() {} + explicit ListIterator(E *e): element(e) {} + + E &operator*() const {return *element;} + E *operator->() const {return element;} + ListIterator &operator++() {element = element->next; return *this;} + ListIterator operator++(int) {ListIterator i(*this); element = element->next; return i;} + friend bool operator==(const ListIterator &i, const ListIterator &j) {return i.element == j.element;} + friend bool operator!=(const ListIterator &i, const ListIterator &j) {return i.element != j.element;} + }; + + + template + #ifndef _WIN32 // Microsoft VC6 bug: std::iterator should support five template arguments + class ConstListIterator: public std::iterator { + #else + class ConstListIterator: public std::iterator { + #endif + const E *element; + + public: + ConstListIterator() {} + ConstListIterator(const ListIterator &i): element(&*i) {} + explicit ConstListIterator(const E *e): element(e) {} + + const E &operator*() const {return *element;} + const E *operator->() const {return element;} + ConstListIterator &operator++() {element = element->next; return *this;} + ConstListIterator operator++(int) {ConstListIterator i(*this); element = element->next; return i;} + friend bool operator==(const ConstListIterator &i, const ConstListIterator &j) {return i.element == j.element;} + friend bool operator!=(const ConstListIterator &i, const ConstListIterator &j) {return i.element != j.element;} + }; + + +// +// Input +// + + +} + +#endif /* kitchensink_h___ */ diff --git a/mozilla/js2/src/lexer.cpp b/mozilla/js2/src/lexer.cpp new file mode 100644 index 00000000000..03a44ea4edd --- /dev/null +++ b/mozilla/js2/src/lexer.cpp @@ -0,0 +1,725 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include "numerics.h" +#include "lexer.h" + +namespace JavaScript +{ + +// Create a new Lexer for lexing the provided source code. The Lexer will +// intern identifiers, keywords, and regular expressions in the designated +// world. + Lexer::Lexer(World &world, const String &source, + const String &sourceLocation, uint32 initialLineNum): + world(world), reader(source, sourceLocation, initialLineNum) + { + nextToken = tokens; + nTokensFwd = 0; +#ifdef DEBUG + nTokensBack = 0; +#endif + lexingUnit = false; + } + + +// Get and return the next token. The token remains valid until the next +// call to this Lexer. If the Reader reached the end of file, return a +// Token whose Kind is end. The caller may alter the value of this Token +// (in particular, take control over the auto_ptr's data), but if it does so, +// the caller is not allowed to unget this Token. +// +// If preferRegExp is true, a / will be preferentially interpreted as +// starting a regular expression; otherwise, a / will be preferentially +// interpreted as division or /=. + const Token + &Lexer::get(bool preferRegExp) + { + const Token &t = peek(preferRegExp); + if (++nextToken == tokens + tokenBufferSize) + nextToken = tokens; + --nTokensFwd; + DEBUG_ONLY(++nTokensBack); + return t; + } + + +// Peek at the next token using the given preferRegExp setting. If that +// token's kind matches the given kind, consume that token and return it. +// Otherwise, do not consume that token and return nil. + const Token * + Lexer::eat(bool preferRegExp, Token::Kind kind) + { + const Token &t = peek(preferRegExp); + if (t.kind != kind) + return 0; + if (++nextToken == tokens + tokenBufferSize) + nextToken = tokens; + --nTokensFwd; + DEBUG_ONLY(++nTokensBack); + return &t; + } + + +// Return the next token without consuming it. +// +// If preferRegExp is true, a / will be preferentially interpreted as +// starting a regular expression; otherwise, a / will be preferentially +// interpreted as division or /=. A subsequent call to peek or get will +// return the same token; that call must be presented with the same value +// for preferRegExp. + const Token & + Lexer::peek(bool preferRegExp) + { + // Use an already looked-up token if there is one. + if (nTokensFwd) { + ASSERT(savedPreferRegExp[nextToken - tokens] == preferRegExp); + } else { + lexToken(preferRegExp); + nTokensFwd = 1; +#ifdef DEBUG + savedPreferRegExp[nextToken - tokens] = preferRegExp; + if (nTokensBack == tokenLookahead) { + nTokensBack = tokenLookahead-1; + if (tokenGuard) + (nextToken >= tokens+tokenLookahead ? + nextToken-tokenLookahead : + nextToken+tokenBufferSize-tokenLookahead)->valid = false; + } +#endif + } + return *nextToken; + } + + +#ifdef DEBUG +// Change the setting of preferRegExp for an already peeked token. +// The token must not be one for which that setting mattered. +// +// THIS IS A DANGEROUS FUNCTION! +// Use it only if you can be prove that the already peeked token does not +// start with a slash. + void + Lexer::redesignate(bool preferRegExp) + { + ASSERT(nTokensFwd); + ASSERT(savedPreferRegExp[nextToken - tokens] != preferRegExp); + ASSERT(!(nextToken->hasKind(Token::regExp) || + nextToken->hasKind(Token::divide) || + nextToken->hasKind(Token::divideEquals))); + savedPreferRegExp[nextToken - tokens] = preferRegExp; + } +#endif + +// Unread the last token. This call may be called to unread at most +// tokenBufferSize tokens at a time (where a peek also counts as temporarily +// reading and unreading one token). When a token that has been unread is +// peeked or read again, the same value must be passed in preferRegExp as for +// the first time that token was read or peeked. + void + Lexer::unget() + { + ASSERT(nTokensBack--); + nTokensFwd++; + if (nextToken == tokens) + nextToken = tokens + tokenBufferSize; + --nextToken; + } + +// Report a syntax error at the backUp-th last character read by the Reader. +// In other words, if backUp is 0, the error is at the next character to be +// read by the Reader; if backUp is 1, the error is at the last character +// read by the Reader, and so forth. + void + Lexer::syntaxError(const char *message, uint backUp) + { + reader.unget(backUp); + reader.error(Exception::syntaxError, widenCString(message), + reader.getPos()); + } + +// Get the next character from the reader, skipping any Unicode format-control +// (Cf) characters. + inline char16 + Lexer::getChar() + { + char16 ch = reader.get(); + if (char16Value(ch) >= firstFormatChar) + ch = internalGetChar(ch); + return ch; + } + +// Helper for getChar() + char16 + Lexer::internalGetChar(char16 ch) + { + while (isFormat(ch)) + ch = reader.get(); + return ch; + } + + +// Peek the next character from the reader, skipping any Unicode +// format-control (Cf) characters, which are read and discarded. + inline char16 + Lexer::peekChar() + { + char16 ch = reader.peek(); + if (char16Value(ch) >= firstFormatChar) + ch = internalPeekChar(ch); + return ch; + } + +// Helper for peekChar() + char16 + Lexer::internalPeekChar(char16 ch) + { + while (isFormat(ch)) { + reader.get(); + ch = reader.peek(); + } + return ch; + } + +// Peek the next character from the reader, skipping any Unicode +// format-control (Cf) characters, which are read and discarded. If the +// peeked character matches ch, read that character and return true; +// otherwise return false. ch must not be null. + bool + Lexer::testChar(char16 ch) + { + ASSERT(ch); // If ch were null, it could match the eof null. + char16 ch2 = peekChar(); + if (ch == ch2) { + reader.get(); + return true; + } + return false; + } + +// A backslash has been read. Read the rest of the escape code. +// Return the interpreted escaped character. Throw an exception if the +// escape is not valid. If unicodeOnly is true, allow only \uxxxx escapes. + char16 + Lexer::lexEscape(bool unicodeOnly) + { + char16 ch = getChar(); + int nDigits; + + if (!unicodeOnly || ch == 'u') + switch (ch) { + case '0': + // Make sure that the next character isn't a digit. + ch = peekChar(); + if (!isASCIIDecimalDigit(ch)) + return 0x00; + // Point to the next character in the error message + getChar(); + break; + + case 'b': + return 0x08; + case 'f': + return 0x0C; + case 'n': + return 0x0A; + case 'r': + return 0x0D; + case 't': + return 0x09; + case 'v': + return 0x0B; + + case 'x': + nDigits = 2; + goto lexHex; + case 'u': + nDigits = 4; + lexHex: + { + uint32 n = 0; + while (nDigits--) { + ch = getChar(); + uint digit; + if (!isASCIIHexDigit(ch, digit)) + goto error; + n = (n << 4) | digit; + } + return static_cast(n); + } + default: + if (!reader.getEof(ch)) { + CharInfo chi(ch); + if (!isAlphanumeric(chi) && !isLineBreak(chi)) + return ch; + } + } + error: + syntaxError("Bad escape code"); + return 0; + } + + +// Read an identifier into s. The initial value of s is ignored and cleared. +// Return true if an escape code has been encountered. +// If allowLeadingDigit is true, allow the first character of s to be a digit, +// just like any continuing identifier character. + bool + Lexer::lexIdentifier(String &s, bool allowLeadingDigit) + { + reader.beginRecording(s); + bool hasEscape = false; + + while (true) { + char16 ch = getChar(); + char16 ch2 = ch; + if (ch == '\\') { + ch2 = lexEscape(true); + hasEscape = true; + } + CharInfo chi2(ch2); + + if (!(allowLeadingDigit ? isIdContinuing(chi2) : + isIdLeading(chi2))) { + if (ch == '\\') + syntaxError("Identifier escape expands into " + "non-identifier character"); + else + reader.unget(); + break; + } + reader.recordChar(ch2); + allowLeadingDigit = true; + } + reader.endRecording(); + return hasEscape; + } + + +// Read a numeric literal into nextToken->chars and nextToken->value. +// Return true if the numeric literal is followed by a unit, but don't read +// the unit yet. + bool + Lexer::lexNumeral() + { + int hasDecimalPoint = 0; + String &s = nextToken->chars; + uint digit; + + reader.beginRecording(s); + char16 ch = getChar(); + if (ch == '0') { + reader.recordChar('0'); + ch = getChar(); + if ((ch&~0x20) == 'X') { + uint32 pos = reader.getPos(); + char16 ch2 = getChar(); + if (isASCIIHexDigit(ch2, digit)) { + reader.recordChar(ch); + do { + reader.recordChar(ch2); + ch2 = getChar(); + } while (isASCIIHexDigit(ch2, digit)); + ch = ch2; + } else + reader.setPos(pos); + goto done; + } else if (isASCIIDecimalDigit(ch)) { + syntaxError("Numeric constant syntax error"); + } + } + while (isASCIIDecimalDigit(ch) || ch == '.' && !hasDecimalPoint++) { + reader.recordChar(ch); + ch = getChar(); + } + if ((ch&~0x20) == 'E') { + uint32 pos = reader.getPos(); + char16 ch2 = getChar(); + char16 sign = 0; + if (ch2 == '+' || ch2 == '-') { + sign = ch2; + ch2 = getChar(); + } + if (isASCIIDecimalDigit(ch2)) { + reader.recordChar(ch); + if (sign) + reader.recordChar(sign); + do { + reader.recordChar(ch2); + ch2 = getChar(); + } while (isASCIIDecimalDigit(ch2)); + ch = ch2; + } else + reader.setPos(pos); + } + + done: + // At this point the reader is just past the character ch, which + // is the first non-formatting character that is not part of the + // number. + reader.endRecording(); + const char16 *sBegin = s.data(); + const char16 *sEnd = sBegin + s.size(); + const char16 *numEnd; + nextToken->value = stringToDouble(sBegin, sEnd, numEnd); + ASSERT(numEnd == sEnd); + reader.unget(); + ASSERT(ch == reader.peek()); + return isIdContinuing(ch) || ch == '\\'; + } + + +// Read a string literal into s. The initial value of s is ignored and +// cleared. The opening quote has already been read into separator. + void + Lexer::lexString(String &s, char16 separator) + { + char16 ch; + + reader.beginRecording(s); + while ((ch = reader.get()) != separator) { + CharInfo chi(ch); + if (!isFormat(chi)) { + if (ch == '\\') + ch = lexEscape(false); + else if (reader.getEof(ch) || isLineBreak(chi)) + syntaxError("Unterminated string literal"); + reader.recordChar(ch); + } + } + reader.endRecording(); + } + + +// Read a regular expression literal. Store the regular expression in +// nextToken->id and the flags in nextToken->chars. +// The opening slash has already been read. + void Lexer::lexRegExp() + { + String s; + char16 prevCh = 0; + + reader.beginRecording(s); + while (true) { + char16 ch = getChar(); + CharInfo chi(ch); + if (reader.getEof(ch) || isLineBreak(chi)) + syntaxError("Unterminated regular expression literal"); + if (prevCh == '\\') { + reader.recordChar(ch); + // Ignore slashes and backslashes immediately after a backslash + prevCh = 0; + } else if (ch != '/') { + reader.recordChar(ch); + prevCh = ch; + } else + break; + } + reader.endRecording(); + nextToken->id = &world.identifiers[s]; + + lexIdentifier(nextToken->chars, true); + } + +// Read a token from the Reader and store it at *nextToken. +// If the Reader reached the end of file, store a Token whose Kind is end. + void Lexer::lexToken(bool preferRegExp) + { + Token &t = *nextToken; + t.lineBreak = false; + t.id = 0; + // Don't really need to waste time clearing this string here + //clear(t.chars); + Token::Kind kind; + + if (lexingUnit) { + lexIdentifier(t.chars, false); + ASSERT(t.chars.size()); + kind = Token::unit; // unit + lexingUnit = false; + } else { + next: + char16 ch = reader.get(); + if (reader.getEof(ch)) { + endOfInput: + t.pos = reader.getPos() - 1; + kind = Token::end; + } else { + char16 ch2; + CharInfo chi(ch); + + switch (cGroup(chi)) { + case CharInfo::FormatGroup: + case CharInfo::WhiteGroup: + goto next; + + case CharInfo::IdGroup: + t.pos = reader.getPos() - 1; + readIdentifier: + { + reader.unget(); + String s; + bool hasEscape = lexIdentifier(s, false); + t.id = &world.identifiers[s]; + kind = hasEscape ? Token::identifier : + t.id->tokenKind; + } + break; + + case CharInfo::NonIdGroup: + case CharInfo::IdContinueGroup: + t.pos = reader.getPos() - 1; + switch (ch) { + case '(': + kind = Token::openParenthesis; // ( + break; + case ')': + kind = Token::closeParenthesis; // ) + break; + case '[': + kind = Token::openBracket; // [ + break; + case ']': + kind = Token::closeBracket; // ] + break; + case '{': + kind = Token::openBrace; // { + break; + case '}': + kind = Token::closeBrace; // } + break; + case ',': + kind = Token::comma; // , + break; + case ';': + kind = Token::semicolon; // ; + break; + case '.': + kind = Token::dot; // . + ch2 = getChar(); + if (isASCIIDecimalDigit(ch2)) { + reader.setPos(t.pos); + goto number; // decimal point + } else if (ch2 == '.') { + kind = Token::doubleDot; // .. + if (testChar('.')) + kind = Token::tripleDot;// ... + } else + reader.unget(); + break; + case ':': + kind = Token::colon; // : + if (testChar(':')) + kind = Token::doubleColon; // :: + break; + case '#': + kind = Token::pound; // # + break; + case '@': + kind = Token::at; // @ + break; + case '?': + kind = Token::question; // ? + break; + + case '~': + kind = Token::complement; // ~ + break; + case '!': + kind = Token::logicalNot; // ! + if (testChar('=')) { + kind = Token::notEqual; // != + if (testChar('=')) + kind = Token::notIdentical; // !== + } + break; + + case '*': + kind = Token::times; // * *= + tryAssignment: + if (testChar('=')) + kind = Token::Kind(kind + + Token::timesEquals - + Token::times); + break; + + case '/': + kind = Token::divide; // / + ch = getChar(); + if (ch == '/') { // // comment + do { + ch = reader.get(); + if (reader.getEof(ch)) + goto endOfInput; + } while (!isLineBreak(ch)); + goto endOfLine; + } else if (ch == '*') { // /*comment*/ + ch = 0; + do { + ch2 = ch; + ch = getChar(); + if (isLineBreak(ch)) { + reader.beginLine(); + t.lineBreak = true; + } else if (reader.getEof(ch)) + syntaxError("Unterminated /* " + "comment"); + } while (ch != '/' || ch2 != '*'); + goto next; + } else { + reader.unget(); + if (preferRegExp) { // Regular expression + kind = Token::regExp; + lexRegExp(); + } else + goto tryAssignment; // /= + } + break; + + case '%': + kind = Token::modulo; // % + goto tryAssignment; // %= + + case '+': + kind = Token::plus; // + + if (testChar('+')) + kind = Token::increment; // ++ + else + goto tryAssignment; // += + break; + + case '-': + kind = Token::minus; // - + ch = getChar(); + if (ch == '-') + kind = Token::decrement; // -- + else if (ch == '>') + kind = Token::arrow; // -> + else { + reader.unget(); + goto tryAssignment; // -= + } + break; + + case '&': + kind = Token::bitwiseAnd; // & && &= &&= + logical: + if (testChar(ch)) + kind = Token::Kind(kind - + Token::bitwiseAnd + + Token::logicalAnd); + goto tryAssignment; + case '^': + kind = Token::bitwiseXor; // ^ ^^ ^= ^^= + goto logical; + case '|': + kind = Token::bitwiseOr; // | || |= ||= + goto logical; + + case '=': + kind = Token::assignment; // = + if (testChar('=')) { + kind = Token::equal; // == + if (testChar('=')) + kind = Token::identical; // === + } + break; + + case '<': + kind = Token::lessThan; // < + if (testChar('<')) { + kind = Token::leftShift; // << + goto tryAssignment; // <<= + } + comparison: + if (testChar('=')) // <= >= + kind = Token::Kind(kind + + Token::lessThanOrEqual - + Token::lessThan); + break; + case '>': + kind = Token::greaterThan; // > + if (testChar('>')) { + kind = Token::rightShift; // >> + if (testChar('>')) + kind = Token::logicalRightShift; // >>> + goto tryAssignment; // >>= >>>= + } + goto comparison; + + case '\\': + goto readIdentifier; // An identifier that + // starts with an escape + + case '\'': + case '"': + kind = Token::string; // 'string' "string" + lexString(t.chars, ch); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + reader.unget(); // Number + number: + kind = Token::number; + lexingUnit = lexNumeral(); + break; + + default: + syntaxError("Bad character"); + } + break; + + case CharInfo::LineBreakGroup: + endOfLine: + reader.beginLine(); + t.lineBreak = true; + goto next; + } + } + } + t.kind = kind; +#ifdef DEBUG + t.valid = true; +#endif + } + +} diff --git a/mozilla/js2/src/lexer.h b/mozilla/js2/src/lexer.h new file mode 100644 index 00000000000..83931748fca --- /dev/null +++ b/mozilla/js2/src/lexer.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef lexer_h___ +#define lexer_h___ + +#include "utilities.h" +#include "formatter.h" +#include "reader.h" +#include "token.h" +#include "world.h" + +namespace JavaScript +{ + + class Lexer { + enum {tokenLookahead = 2}; // Number of tokens that can be + // simultaneously live +#ifdef DEBUG + enum {tokenGuard = 10}; // Number of invalid tokens added to + // circular token buffer to catch + // references to old tokens +#else + enum {tokenGuard = 0}; // Number of invalid tokens added to + // circular token buffer to catch + // references to old tokens +#endif + // Token lookahead buffer size + enum {tokenBufferSize = tokenLookahead + tokenGuard}; + + Token tokens[tokenBufferSize]; // Circular buffer of recently read or + // lookahead tokens + Token *nextToken; // Address of next Token in the + // circular buffer to be returned by + // get() + int nTokensFwd; // Net number of Tokens on which + // unget() has been called; these + // Tokens are ahead of nextToken +#ifdef DEBUG + int nTokensBack; // Number of Tokens on which unget() + // can be called; these Tokens are + // beind nextToken + bool savedPreferRegExp[tokenBufferSize]; // Circular buffer of saved + // values of preferRegExp to + // get() calls +#endif + bool lexingUnit; // True if lexing a unit identifier + // immediately following a number + public: + World &world; + Reader reader; + + Lexer(World &world, const String &source, const String &sourceLocation, + uint32 initialLineNum = 1); + + const Token &get(bool preferRegExp); + const Token *eat(bool preferRegExp, Token::Kind kind); + const Token &peek(bool preferRegExp); + void redesignate(bool preferRegExp); + void unget(); + uint32 getPos() const; + + private: + void syntaxError(const char *message, uint backUp = 1); + char16 getChar(); + char16 internalGetChar(char16 ch); + char16 peekChar(); + char16 internalPeekChar(char16 ch); + bool testChar(char16 ch); + + char16 lexEscape(bool unicodeOnly); + bool lexIdentifier(String &s, bool allowLeadingDigit); + bool lexNumeral(); + void lexString(String &s, char16 separator); + void lexRegExp(); + void lexToken(bool preferRegExp); + }; + +#ifndef DEBUG + inline void Lexer::redesignate(bool) {} // See description for the DEBUG + // version inside parser.cpp +#endif + + // Return the position of the first character of the next token, + // which must have been peeked. + inline uint32 + Lexer::getPos() const + { + ASSERT(nTokensFwd); + return nextToken->getPos(); + } + +} + +#endif /* lexer_h___ */ diff --git a/mozilla/js2/src/mem.cpp b/mozilla/js2/src/mem.cpp new file mode 100644 index 00000000000..0121df13b36 --- /dev/null +++ b/mozilla/js2/src/mem.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include + +#include "mem.h" + +namespace JavaScript +{ + +// +// Zones +// + +// #define DEBUG_ZONE to allocate each object in its own malloc block. +// This allows tools such as Purify to do bounds checking on all blocks. + +// Construct a Zone that allocates memory in chunks of the given size. + Zone::Zone(size_t blockSize): + headers(0), freeBegin(0), freeEnd(0), blockSize(blockSize) + { + ASSERT(blockSize && !(blockSize & basicAlignment-1)); + } + +// Deallocate the Zone's blocks. + void + Zone::clear() + { + Header *h = headers; + while (h) { + Header *next = h->next; + STD::free(h); + h = next; + } + headers = 0; + } + + +// Allocate a fully aligned block of the given size. +// Throw bad_alloc if out of memory, without corrupting any of the Zone data +// structures. + void * + Zone::newBlock(size_t size) + { + Header *h = static_cast
(STD::malloc(sizeof(Header) + size)); + h->next = headers; + headers = h; + return h+1; + } + + +// Allocate a naturally-aligned object of the given size (in bytes). Throw +// bad_alloc if out of memory, without corrupting any of the Zone data +// structures. + void * + Zone::allocate(size_t size) + { + ASSERT(size); // Can't allocate zero-size blocks. +#ifdef DEBUG_ZONE + return newBlock(size); +#else + // Round up to natural alignment if necessary + size = size + (basicAlignment-1) & -basicAlignment; + char *p = freeBegin; + size_t freeBytes = static_cast(freeEnd - p); + + if (size > freeBytes) { + // If freeBytes is at least a quarter of blockSize, allocate + //a separate block. + if (freeBytes<<2 >= blockSize || size >= blockSize) + return newBlock(size); + + p = static_cast(newBlock(blockSize)); + freeEnd = p + blockSize; + } + freeBegin = p + size; + return p; +#endif + } + +// Same as allocate but does not align size up to basicAlignment. Thus, the +// next object allocated in the zone will immediately follow this one if it +// falls in the same zone block. +// Use this when all objects in the zone have the same size. + void * + Zone::allocateUnaligned(size_t size) + { + ASSERT(size); // Can't allocate zero-size blocks. +#ifdef DEBUG_ZONE + return newBlock(size); +#else + char *p = freeBegin; + size_t freeBytes = static_cast(freeEnd - p); + + if (size > freeBytes) { + // If freeBytes is at least a quarter of blockSize, allocate a + // separate block. + if (freeBytes<<2 >= blockSize || size >= blockSize) + return newBlock(size); + + p = static_cast(newBlock(blockSize)); + freeEnd = p + blockSize; + } + freeBegin = p + size; + return p; +#endif + } + +// +// Arenas +// + struct Arena::DestructorEntry : ArenaObject { + DestructorEntry *next; // Next destructor registration in linked list + void (*destructor)(void *); // Destructor function + void *object; // Object on which to call the destructor + + DestructorEntry (void (*destructor)(void *), void *object) : + destructor(destructor), object(object) {} + }; + +// Call the Arena's registered destructors. + void + Arena::runDestructors() + { + DestructorEntry *e = destructorEntries; + while (e) { + e->destructor(e->object); + e = e->next; + } + destructorEntries = 0; + } + +// Ensure that object's destructor is called at the time the arena is +// deallocated or cleared. The destructors will be called in reverse order of +// being registered. registerDestructor might itself runs out of memory, in +// which case it immediately calls object's destructor before throwing +// bad_alloc. + void + Arena::newDestructorEntry(void (*destructor)(void *), void *object) + { + try { + DestructorEntry *e = new(*this) DestructorEntry(destructor, object); + e->next = destructorEntries; + destructorEntries = e; + } catch (...) { + destructor(object); + throw; + } + } + +} diff --git a/mozilla/js2/src/mem.h b/mozilla/js2/src/mem.h new file mode 100644 index 00000000000..2cf01750a45 --- /dev/null +++ b/mozilla/js2/src/mem.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef mem_h___ +#define mem_h___ + +#include "systemtypes.h" +#include "stlcfg.h" +#include "utilities.h" + +namespace JavaScript +{ + +// +// Zones +// + +// A zone is a region of memory from which objects can be allocated +// individually. +// The memory in a zone is deallocated when the zone is deallocated or its +// clear method called. + + class Zone { + union Header { + Header *next; // Next block header in linked list + // Padding to ensure following block is fully aligned + char padding[basicAlignment]; + };// Block data follows header + + Header *headers; // Linked list of allocated blocks + char *freeBegin; // Pointer to free bytes left in current block + char *freeEnd; // Pointer to end of free bytes left in current block + size_t blockSize; // Size of individual arena blocks + + public: + explicit Zone(size_t blockSize = 1024); + private: + Zone(const Zone&); // No copy constructor + void operator=(const Zone&); // No assignment operator + public: + void clear(); + ~Zone() {clear();} + + private: + void *newBlock(size_t size); + public: + void *allocate(size_t size); + void *allocateUnaligned(size_t size); + }; + +// +// Arenas +// + +#ifndef _WIN32 + // Pretend that obj points to a value of class T and call obj's destructor. + template + void classDestructor(void *obj) + { + static_cast(obj)->~T(); + } +#else // Microsoft Visual C++ 6.0 bug workaround + template + struct DestructorHolder + { + static void destroy(void *obj) {static_cast(obj)->~T();} + }; +#endif + +// An arena is a region of memory from which objects either derived from +// ArenaObject or allocated using a ArenaAllocator can be allocated. Deleting +// these objects individually runs the destructors, if any, but does not +// deallocate the memory. On the other hand, the entire arena can be +// deallocated as a whole. +// +// One may also allocate other objects in an arena by using the Arena +// specialization of the global operator new. However, be careful not to +// delete any such objects explicitly! +// +// Destructors can be registered for objects (or parts of objects) allocated +// in the arena. These destructors are called, in reverse order of being +// registered, at the time the arena is deallocated or cleared. When +// registering destructors for an object O be careful not to delete O manually +// because that would run its destructor twice. + class Arena: public Zone { + struct DestructorEntry; + + // Linked list of destructor registrations, ordered from most to + // least recently registered + DestructorEntry *destructorEntries; + + public: + explicit Arena(size_t blockSize = 1024): + Zone(blockSize), destructorEntries(0) {} + private: + void runDestructors(); + public: + void clear() {runDestructors(); Zone::clear();} + ~Arena() {runDestructors();} + + private: + void newDestructorEntry(void (*destructor)(void *), void *object); + public: + // Ensure that object's destructor is called at the time the arena is + // deallocated or cleared. + // The destructors will be called in reverse order of being registered. + // registerDestructor might itself runs out of memory, in which case + // it immediately + // calls object's destructor before throwing bad_alloc. +#ifndef _WIN32 + template void registerDestructor(T *object) { + newDestructorEntry(&classDestructor, object); + } +#else + template void registerDestructor(T *object) { + newDestructorEntry(&DestructorHolder::destroy, object); + } +#endif + }; + + + // Objects derived from this class will be contained in the Arena + // passed to the new operator. + struct ArenaObject { + void *operator new(size_t size, Arena &arena) { + return arena.allocate(size); + } + void *operator new[](size_t size, Arena &arena) { + return arena.allocate(size); + } + void operator delete(void *, Arena &) {} + void operator delete[](void *, Arena &) {} + private: + void operator delete(void *, size_t) {} + void operator delete[](void *) {} + }; + + + // Objects allocated by passing this class to standard containers will + // be contained in the Arena passed to the ArenaAllocator's constructor. + template class ArenaAllocator { + Arena &arena; + + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + + static pointer address(reference r) {return &r;} + static const_pointer address(const_reference r) {return &r;} + + ArenaAllocator(Arena &arena): arena(arena) {} + template ArenaAllocator(const ArenaAllocator &u) : + arena(u.arena) {} + + pointer allocate(size_type n, const void *hint = 0) { + return static_cast(arena.allocate(n*sizeof(T))); + } + static void deallocate(pointer, size_type) {} + + static void construct(pointer p, const T &val) {new(p) T(val);} + static void destroy(pointer p) {p->~T();} + +#ifdef __GNUC__ // why doesn't g++ support numeric_limits? + static size_type max_size() {return size_type(-1) / sizeof(T);} +#else + static size_type max_size() { + return std::numeric_limits::max() / sizeof(T); + } +#endif + + template struct rebind {typedef ArenaAllocator other;}; + }; + +// +// Pools +// + + // A Pool holds a collection of objects of the same type. These + // objects can be allocated and deallocated inexpensively. + // To allocate a T, use new(pool) T(...), where pool has type Pool. + // To deallocate a T, use pool.destroy(t), where t has type T*. + template class Pool: public Zone { + struct FreeList { + FreeList *next; // Next item in linked list of freed objects + }; + + STATIC_CONST(size_t, entrySize = sizeof(T) >= sizeof(FreeList *) ? + sizeof(T) : sizeof(FreeList *)); + + FreeList *freeList; // Head of linked list of freed objects + + public: + // clumpSize is the number of T's that are allocated at a time. + explicit Pool(size_t clumpSize) : + Zone(clumpSize * entrySize), freeList(0) {} + + // Allocate memory for a single T. Use this with a placement new + // operator to create a new T. + void *allocate() { + if (freeList) { + FreeList *p = freeList; + freeList = p->next; + return p; + } + return allocateUnaligned(entrySize); + } + void deallocate(void *t) { + FreeList *p = static_cast(t); + p->next = freeList; + freeList = p; + } + + void destroy(T *t) {ASSERT(t); t->~T(); deallocate(t);} + }; +} + +inline void *operator new(size_t size, JavaScript::Arena &arena) { + return arena.allocate(size); +} +#ifndef _WIN32 +// Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished +inline void *operator new[](size_t size, JavaScript::Arena &arena) { + return arena.allocate(size); +} +#endif + +// Global delete operators. These are only called in the rare cases that a +// constructor throws an exception and has to undo an operator new. +// An explicit delete statement will never invoke these. +inline void operator delete(void *, JavaScript::Arena &) {} +// Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished +#ifndef _WIN32 + inline void operator delete[](void *, JavaScript::Arena &) {} +#endif + +template +inline void *operator new(size_t DEBUG_ONLY(size), JavaScript::Pool &pool) { + ASSERT(size == sizeof(T)); return pool.allocate(); +} +template +inline void operator delete(void *t, JavaScript::Pool &pool) { + pool.deallocate(t); +} +//#endif + +#endif /* mem_h___ */ diff --git a/mozilla/js2/src/nodefactory.h b/mozilla/js2/src/nodefactory.h index b45956c4551..cfb19cdb9a5 100644 --- a/mozilla/js2/src/nodefactory.h +++ b/mozilla/js2/src/nodefactory.h @@ -1,289 +1,374 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#ifndef nodefactory_h -#define nodefactory_h +#ifndef nodefactory_h___ +#define nodefactory_h___ #include "utilities.h" #include -#include "parser.h" namespace JavaScript { class NodeFactory { private: + NodeFactory(Arena& arena) : arena(arena) {} static NodeFactory *state; - - NodeFactory(Arena& arena) : arena(arena) { - } - - // state variables - Arena &arena; - public: - static void Init(Arena& arena) { + static void + Init(Arena& arena) { state = new NodeFactory(arena); } - static Arena& getArena() { + static Arena & + getArena() { return NodeFactory::state->arena; } - static IdentifierExprNode *Identifier(const Token &t) { + static IdentifierExprNode * + Identifier(const Token &t) { return new(getArena()) IdentifierExprNode(t); } - static IdentifierList *ListedIdentifier(String &name) { + static IdentifierList * + ListedIdentifier(String &name) { return new(getArena()) IdentifierList(*new StringAtom(name)); } #if 0 - static QualifiedIdentifierNode QualifiedIdentifier( Node qualifier, IdentifierNode identifier ) { + static QualifiedIdentifierNode + QualifiedIdentifier(Node qualifier, IdentifierNode identifier ) { return new QualifiedIdentifierNode(qualifier,identifier); } - static LiteralNullNode LiteralNull() { + static LiteralNullNode + LiteralNull() { return new LiteralNullNode(); } - static LiteralBooleanNode LiteralBoolean(boolean value) { + static LiteralBooleanNode + LiteralBoolean(boolean value) { return new LiteralBooleanNode(value); } - static LiteralArrayNode LiteralArray( Node elementlist ) { + static LiteralArrayNode + LiteralArray(Node elementlist) { return new LiteralArrayNode(elementlist); } #endif - static ExprPairList *LiteralField(ExprNode *name = 0, ExprNode *value = 0) { + static ExprPairList * + LiteralField(ExprNode *name = 0, ExprNode *value = 0) { return new(getArena()) ExprPairList(name,value); } - static NumberExprNode * LiteralNumber(const Token &t) { + static NumberExprNode * + LiteralNumber(const Token &t) { return new(getArena()) NumberExprNode(t); } #if 0 - static LiteralObjectNode LiteralObject( Node fieldlist ) { + static LiteralObjectNode + LiteralObject(Node fieldlist) { return new LiteralObjectNode(fieldlist); } - static LiteralRegExpNode LiteralRegExp( String value ) { + static LiteralRegExpNode + LiteralRegExp(String value) { return new LiteralRegExpNode(value); } #endif - static StringExprNode *LiteralString(uint32 pos, ExprNode::Kind kind, String &str) { + static StringExprNode * + LiteralString(uint32 pos, ExprNode::Kind kind, String &str) { return new(getArena()) StringExprNode(pos,kind,str); } #if 0 - static LiteralTypeNode LiteralType( Type type ) { + static LiteralTypeNode + LiteralType(Type type) { return new LiteralTypeNode(type); } - static LiteralUndefinedNode LiteralUndefined() { + static LiteralUndefinedNode + LiteralUndefined() { return new LiteralUndefinedNode(); } - static FunctionExpressionNode FunctionExpression( Node name, Node signature, Node body ) { + static FunctionExpressionNode + FunctionExpression(Node name, Node signature, Node body ) { return new FunctionExpressionNode(name,signature,body); } - static AnnotatedDefinitionNode AnnotatedDefinition( Node attributes, Node definition ) { + static AnnotatedDefinitionNode + AnnotatedDefinition(Node attributes, Node definition) { return new AnnotatedDefinitionNode(attributes,definition); } - static AttributeDefinitionNode AttributeDefinition( Node name, int kind, Node value ) { + static AttributeDefinitionNode + AttributeDefinition(Node name, int kind, Node value) { return new AttributeDefinitionNode(name,kind,value); } - static AttributeListNode AttributeList( Node item, Node list ) { + static AttributeListNode + AttributeList(Node item, Node list) { return new AttributeListNode(item,list); } - static UnitExpressionNode UnitExpression( Node value, Node type ) { + static UnitExpressionNode + UnitExpression(Node value, Node type) { return new UnitExpressionNode(value,type); } - static ThisExpressionNode ThisExpression() { + static ThisExpressionNode + ThisExpression() { return new ThisExpressionNode(); } - static SuperExpressionNode SuperExpression() { + static SuperExpressionNode + SuperExpression() { return new SuperExpressionNode(); } - static EvalExpressionNode EvalExpression( Node expr ) { + static EvalExpressionNode + EvalExpression(Node expr) { return new EvalExpressionNode(expr); } - static ListNode List( Node list, Node item ) { + static ListNode + List(Node list, Node item) { return new ListNode(list,item); } - static PostfixExpressionNode PostfixExpression( int op, Node expr ) { + static PostfixExpressionNode + PostfixExpression(int op, Node expr) { return new PostfixExpressionNode(op,expr); } - static NewExpressionNode NewExpression( Node member ) { + static NewExpressionNode + NewExpression(Node member) { return new NewExpressionNode(member); } - static CallExpressionNode CallExpression( Node member, Node args ) { + static CallExpressionNode + CallExpression(Node member, Node args) { return new CallExpressionNode(member,args); } - static IndexedMemberExpressionNode IndexedMemberExpression( Node base, Node member ) { + static IndexedMemberExpressionNode + IndexedMemberExpression(Node base, Node member) { return new IndexedMemberExpressionNode(base,member); } - static MemberExpressionNode MemberExpression( Node base, Node name ) { + static MemberExpressionNode + MemberExpression(Node base, Node name) { return new MemberExpressionNode(base,name); } - static CoersionExpressionNode CoersionExpression( Node expr, Node type ) { + static CoersionExpressionNode + CoersionExpression(Node expr, Node type) { return new CoersionExpressionNode(expr,type); } - static UnaryExpressionNode UnaryExpression( int op, Node expr ) { + static UnaryExpressionNode + UnaryExpression(int op, Node expr) { return new UnaryExpressionNode(op,expr); } - static BinaryExpressionNode BinaryExpression( int op, Node lhs, Node rhs ) { + static BinaryExpressionNode + BinaryExpression(int op, Node lhs, Node rhs) { return new BinaryExpressionNode(op,lhs,rhs); } - static ConditionalExpressionNode ConditionalExpression( Node cond, Node thenexpr, Node elseexpr ) { + static ConditionalExpressionNode + ConditionalExpression(Node cond, Node thenexpr, Node elseexpr) { return new ConditionalExpressionNode(cond,thenexpr,elseexpr); } - static AssignmentExpressionNode AssignmentExpression( Node lhs, int op, Node rhs ) { + static AssignmentExpressionNode + AssignmentExpression(Node lhs, int op, Node rhs) { return new AssignmentExpressionNode(lhs,op,rhs); } - static StatementListNode StatementList( StatementListNode list, Node item ) { + static StatementListNode + StatementList (StatementListNode list, Node item ) { return new StatementListNode(list,item); } - static EmptyStatementNode EmptyStatement() { + static EmptyStatementNode + EmptyStatement() { return new EmptyStatementNode(); } - static ExpressionStatementNode ExpressionStatement( Node expr ) { + static ExpressionStatementNode + ExpressionStatement(Node expr) { return new ExpressionStatementNode(expr); } - static AnnotatedBlockNode AnnotatedBlock( Node attributes, Node definition ) { + static AnnotatedBlockNode + AnnotatedBlock(Node attributes, Node definition) { return new AnnotatedBlockNode(attributes,definition); } - static LabeledStatementNode LabeledStatement( Node label, Node statement ) { + static LabeledStatementNode + LabeledStatement(Node label, Node statement) { return new LabeledStatementNode(label,statement); } - static IfStatementNode IfStatement( Node test, Node tblock, Node eblock ) { + static IfStatementNode + IfStatement(Node test, Node tblock, Node eblock) { return new IfStatementNode(test,tblock,eblock); } - static SwitchStatementNode SwitchStatement( Node expr, Node statements ) { + static SwitchStatementNode + SwitchStatement(Node expr, Node statements) { return new SwitchStatementNode(expr,statements); } - static DefaultStatementNode DefaultStatement() { + static DefaultStatementNode + DefaultStatement() { return new DefaultStatementNode(); } - static DoStatementNode DoStatement( Node block, Node expr ) { + static DoStatementNode + DoStatement(Node block, Node expr) { return new DoStatementNode(block,expr); } - static WhileStatementNode WhileStatement( Node expr, Node statement ) { + static WhileStatementNode + WhileStatement(Node expr, Node statement) { return new WhileStatementNode(expr,statement); } - static ForInStatementNode ForInStatement( Node expr1, Node expr2, Node statement ) { + static ForInStatementNode + ForInStatement(Node expr1, Node expr2, Node statement) { return new ForInStatementNode(expr1,expr2,statement); } - static ForStatementNode ForStatement( Node expr1, Node expr2, Node expr3, Node statement ) { + static ForStatementNode + ForStatement(Node expr1, Node expr2, Node expr3, Node statement) { return new ForStatementNode(expr1,expr2,expr3,statement); } - static WithStatementNode WithStatement( Node expr, Node statement ) { + static WithStatementNode + WithStatement(Node expr, Node statement) { return new WithStatementNode(expr,statement); } - static ContinueStatementNode ContinueStatement(Node expr) { + static ContinueStatementNode + ContinueStatement(Node expr) { return new ContinueStatementNode(expr); } - static BreakStatementNode BreakStatement(Node expr) { + static BreakStatementNode + BreakStatement(Node expr) { return new BreakStatementNode(expr); } - static ReturnStatementNode ReturnStatement( Node expr ) { + static ReturnStatementNode + ReturnStatement(Node expr) { return new ReturnStatementNode(expr); } - static ThrowStatementNode ThrowStatement(Node list) { + static ThrowStatementNode + ThrowStatement(Node list) { return new ThrowStatementNode(list); } - static TryStatementNode TryStatement(Node tryblock, Node catchlist, Node finallyblock) { + static TryStatementNode + TryStatement(Node tryblock, Node catchlist, Node finallyblock) { return new TryStatementNode(tryblock,catchlist,finallyblock); } - static CatchClauseNode CatchClause(Node parameter, Node block) { + static CatchClauseNode + CatchClause(Node parameter, Node block) { return new CatchClauseNode(parameter,block); } - static FinallyClauseNode FinallyClause( Node block ) { + static FinallyClauseNode + FinallyClause(Node block) { return new FinallyClauseNode(block); } - static IncludeStatementNode IncludeStatement( Node list ) { + static IncludeStatementNode + IncludeStatement(Node list) { return new IncludeStatementNode(list); } - static UseStatementNode UseStatement( Node expr ) { + static UseStatementNode + UseStatement(Node expr) { return new UseStatementNode(expr); } - - static ImportDefinitionNode ImportDefinition( Node item, Node list ) { + static ImportDefinitionNode + ImportDefinition(Node item, Node list) { return new ImportDefinitionNode(item,list); } - static ImportBindingNode ImportBinding( Node identifer, Node item ) { + static ImportBindingNode + ImportBinding(Node identifer, Node item) { return new ImportBindingNode(identifer,item); } - static ExportDefinitionNode ExportDefinition( Node list ) { + static ExportDefinitionNode + ExportDefinition(Node list) { return new ExportDefinitionNode(list); } - static ExportBindingNode ExportBinding( Node name, Node value ) { + static ExportBindingNode + ExportBinding(Node name, Node value) { return new ExportBindingNode(name,value); } - static VariableDefinitionNode VariableDefinition( int kind, Node list ) { + static VariableDefinitionNode + VariableDefinition(int kind, Node list) { return new VariableDefinitionNode(kind,list); } - static VariableBindingNode VariableBinding( Node identifier, Node initializer ) { + static VariableBindingNode + VariableBinding(Node identifier, Node initializer) { return new VariableBindingNode(identifier,initializer); } - static TypedVariableNode TypedVariable( Node identifier, Node type ) { + static TypedVariableNode + TypedVariable(Node identifier, Node type) { return new TypedVariableNode(identifier,type); } - static FunctionDefinitionNode FunctionDefinition( Node decl, Node body ) { + static FunctionDefinitionNode + FunctionDefinition(Node decl, Node body) { return new FunctionDefinitionNode(decl,body); } - static FunctionDeclarationNode FunctionDeclaration( Node name, Node signature ) { + static FunctionDeclarationNode + FunctionDeclaration(Node name, Node signature) { return new FunctionDeclarationNode(name,signature); } - static FunctionNameNode FunctionName( int kind, Node name ) { + static FunctionNameNode + FunctionName(int kind, Node name) { return new FunctionNameNode(kind,name); } - static RestParameterNode RestParameter( Node expr ) { + static RestParameterNode + RestParameter(Node expr) { return new RestParameterNode(expr); } - static ParameterNode Parameter( Node identifer, Node type ) { + static ParameterNode + Parameter(Node identifer, Node type) { return new ParameterNode(identifer,type); } #endif - static VariableBinding *Parameter(ExprNode *name, ExprNode *type) { - return new(getArena()) VariableBinding(0, name, type); + static VariableBinding * + Parameter(ExprNode *name, ExprNode *type, bool constant) { + return new(getArena()) VariableBinding(0, name, type, 0, constant); } #if 0 - static VariableBinding *NamedParameter( StringExprNode *name, ParseNode *parameter ) { - return new(Arena()) NamedParameterNode(name, parameter); + static VariableBinding * + NamedParameter(StringExprNode *name, ParseNode *parameter) { + return new(Arena()) NamedParameterNode(name, parameter); } - static ClassDeclarationNode ClassDeclaration( Node name ) { + static ClassDeclarationNode + ClassDeclaration(Node name) { return new ClassDeclarationNode(name); } - static ClassDefinitionNode ClassDefinition( Node name, Node interfaces, Node statements ) { + static ClassDefinitionNode + ClassDefinition(Node name, Node interfaces, Node statements) { return new ClassDefinitionNode(name,interfaces,statements); } - static InheritanceNode Inheritance( Node baseclass, Node interfaces ) { + static InheritanceNode + Inheritance(Node baseclass, Node interfaces) { return new InheritanceNode(baseclass,interfaces); } - static InterfaceDeclarationNode InterfaceDeclaration( Node name ) { + static InterfaceDeclarationNode + InterfaceDeclaration(Node name) { return new InterfaceDeclarationNode(name); } - static InterfaceDefinitionNode InterfaceDefinition( Node name, Node interfaces, Node statements ) { + static InterfaceDefinitionNode + InterfaceDefinition(Node name, Node interfaces, Node statements) { return new InterfaceDefinitionNode(name,interfaces,statements); } - static NamespaceDefinitionNode NamespaceDefinition( Node identifier, Node list ) { + static NamespaceDefinitionNode + NamespaceDefinition(Node identifier, Node list) { return new NamespaceDefinitionNode(identifier,list); } - static LanguageDeclarationNode LanguageDeclaration( Node list ) { + static LanguageDeclarationNode + LanguageDeclaration(Node list) { return new LanguageDeclarationNode(list); } - static PackageDefinitionNode PackageDefinition( Node name, Node block ) { + static PackageDefinitionNode + PackageDefinition(Node name, Node block) { return new PackageDefinitionNode(name,block); } - static ProgramNode Program( Node statements ) { + static ProgramNode + Program(Node statements) { return new ProgramNode(statements); } #endif diff --git a/mozilla/js2/src/numerics.cpp b/mozilla/js2/src/numerics.cpp index b70d319bbbe..2c12e5ac4a9 100644 --- a/mozilla/js2/src/numerics.cpp +++ b/mozilla/js2/src/numerics.cpp @@ -1,34 +1,47 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. - +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #include #include #include #include "numerics.h" -#include "jstypes.h" - -namespace JS = JavaScript; -using namespace JavaScript; -using namespace JSTypes; +//#include "jstypes.h" +//using namespace JSTypes; +namespace JavaScript +{ + // // Portable double-precision floating point to string and back conversions // @@ -128,9 +141,9 @@ using namespace JSTypes; // avoids underflows on inputs whose result does not underflow. #ifdef IS_LITTLE_ENDIAN - #define IEEE_8087 +# define IEEE_8087 #else - #define IEEE_MC68k +# define IEEE_MC68k #endif @@ -139,21 +152,21 @@ using namespace JSTypes; // differently: the 32 bit words are in little endian byte order, the two words // are stored in big endian`s way. #if defined (IEEE_8087) && !defined(__arm) - #define word0(x) ((uint32 *)&x)[1] - #define word1(x) ((uint32 *)&x)[0] +# define word0(x) ((uint32 *)&x)[1] +# define word1(x) ((uint32 *)&x)[0] #else - #define word0(x) ((uint32 *)&x)[0] - #define word1(x) ((uint32 *)&x)[1] +# define word0(x) ((uint32 *)&x)[0] +# define word1(x) ((uint32 *)&x)[1] #endif // The following definition of Storeinc is appropriate for MIPS processors. // An alternative that might be better on some machines is // #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) #if defined(IEEE_8087) - #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else - #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif @@ -189,19 +202,19 @@ using namespace JSTypes; #define Int_max 14 #define Infinite(x) (word0(x) == 0x7ff00000) // sufficient test for here #ifndef NO_IEEE_Scale - #define Avoid_Underflow +# define Avoid_Underflow #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #ifdef JS_THREADSAFE - static PRLock *freelist_lock; - #define ACQUIRE_DTOA_LOCK(n) PR_Lock(freelist_lock) - #define FREE_DTOA_LOCK(n) PR_Unlock(freelist_lock) + static PRLock *freelist_lock; +# define ACQUIRE_DTOA_LOCK(n) PR_Lock(freelist_lock) +# define FREE_DTOA_LOCK(n) PR_Unlock(freelist_lock) #else - #define ACQUIRE_DTOA_LOCK(n) - #define FREE_DTOA_LOCK(n) +# define ACQUIRE_DTOA_LOCK(n) +# define FREE_DTOA_LOCK(n) #endif @@ -210,23 +223,24 @@ using namespace JSTypes; // -double JS::positiveInfinity; -double JS::negativeInfinity; -double JS::nan; + double positiveInfinity; + double negativeInfinity; + double nan; -struct InitNumerics {InitNumerics();}; -static InitNumerics initNumerics; + struct InitNumerics {InitNumerics();}; + static InitNumerics initNumerics; -InitNumerics::InitNumerics() -{ - word0(positiveInfinity) = Exp_mask; - word1(positiveInfinity) = 0; - word0(negativeInfinity) = Exp_mask | Sign_bit; - word1(negativeInfinity) = 0; - word0(nan) = 0x7FFFFFFF; - word1(nan) = 0xFFFFFFFF; -} + InitNumerics::InitNumerics() + { + word0(positiveInfinity) = Exp_mask; + word1(positiveInfinity) = 0; + word0(negativeInfinity) = Exp_mask | Sign_bit; + word1(negativeInfinity) = 0; + word0(nan) = 0x7FFFFFFF; + word1(nan) = 0xFFFFFFFF; + } +/* // had to move these here since they depend upon the values // initialized above, and we can't guarantee order other than // lexically in a single file. @@ -239,419 +253,424 @@ const JSValue JSTypes::kNegativeZero = JSValue(-0.0); const JSValue JSTypes::kPositiveZero = JSValue(0.0); const JSValue JSTypes::kNegativeInfinity = JSValue(negativeInfinity); const JSValue JSTypes::kPositiveInfinity = JSValue(positiveInfinity); - +*/ // // Portable double-precision floating point to string and back conversions // -// Return the absolute difference between x and the adjacent greater-magnitude double number (ignoring exponent overflows). -double JS::ulp(double x) -{ - int32 L; - double a; +// Return the absolute difference between x and the adjacent greater-magnitude +// double number (ignoring exponent overflows). + double ulp(double x) + { + int32 L; + double a; - L = int32((word0(x) & Exp_mask) - (P-1)*Exp_msk1); + L = int32((word0(x) & Exp_mask) - (P-1)*Exp_msk1); #ifndef Sudden_Underflow - if (L > 0) { + if (L > 0) { #endif - word0(a) = uint32(L); - word1(a) = 0; -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(a) = 0x80000u >> L; + word0(a) = uint32(L); word1(a) = 0; +#ifndef Sudden_Underflow } else { - word0(a) = 0; - L -= Exp_shift; - word1(a) = L >= 31 ? 1u : 1u << (31 - L); + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000u >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1u : 1u << (31 - L); + } } - } #endif - return a; -} + return a; + } // Return the number (0 through 32) of most significant zero bits in x. -int JS::hi0bits(uint32 x) -{ - int k = 0; + int hi0bits(uint32 x) + { + int k = 0; - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; -} // Return the number (0 through 32) of least significant zero bits in y. // Also shift y to the right past these 0 through 32 zeros so that y's // least significant bit will be set unless y was originally zero. -static int lo0bits(uint32 &y) -{ - int k; - uint32 x = y; + static int lo0bits(uint32 &y) + { + int k; + uint32 x = y; - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - y = x >> 1; - return 1; + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + y = x >> 1; + return 1; + } + y = x >> 2; + return 2; } - y = x >> 2; - return 2; + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x & 1) + return 32; + } + y = x; + return k; } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x & 1) - return 32; - } - y = x; - return k; -} -uint32 *JS::BigInt::freeLists[maxLgGrossSize+1]; + uint32 *BigInt::freeLists[maxLgGrossSize+1]; -// Allocate a BigInt with 2^lgGrossSize words. The BigInt must not currently contain a number. -void JS::BigInt::allocate(uint lgGrossSize) -{ - ASSERT(lgGrossSize <= maxLgGrossSize); +// Allocate a BigInt with 2^lgGrossSize words. The BigInt must not currently +// contain a number. + void BigInt::allocate(uint lgGrossSize) + { + ASSERT(lgGrossSize <= maxLgGrossSize); - BigInt::lgGrossSize = lgGrossSize; - negative = false; - grossSize = 1u << lgGrossSize; - size = 0; - words = 0; - ACQUIRE_DTOA_LOCK(0); - uint32 *w = freeLists[lgGrossSize]; - if (w) { - freeLists[lgGrossSize] = *reinterpret_cast(w); - FREE_DTOA_LOCK(0); - } else { - FREE_DTOA_LOCK(0); - w = static_cast(STD::malloc(max(uint32(grossSize*sizeof(uint32)), uint32(sizeof(uint32 *))))); - if (!w) { - std::bad_alloc outOfMemory; - throw outOfMemory; - } + BigInt::lgGrossSize = lgGrossSize; + negative = false; + grossSize = 1u << lgGrossSize; + size = 0; + words = 0; + ACQUIRE_DTOA_LOCK(0); + uint32 *w = freeLists[lgGrossSize]; + if (w) { + freeLists[lgGrossSize] = *reinterpret_cast(w); + FREE_DTOA_LOCK(0); + } else { + FREE_DTOA_LOCK(0); + w = static_cast(STD::malloc(max(uint32(grossSize * + sizeof(uint32)), + uint32(sizeof(uint32 *))))); + if (!w) { + std::bad_alloc outOfMemory; + throw outOfMemory; + } + } + words = w; } - words = w; -} // Recycle this BigInt's words array, which must be non-nil. -void JS::BigInt::recycle() -{ - ASSERT(words); - uint bucket = lgGrossSize; - uint32 *w = words; - ACQUIRE_DTOA_LOCK(0); - *reinterpret_cast(w) = freeLists[bucket]; - freeLists[bucket] = w; - FREE_DTOA_LOCK(0); -} + void BigInt::recycle() + { + ASSERT(words); + uint bucket = lgGrossSize; + uint32 *w = words; + ACQUIRE_DTOA_LOCK(0); + *reinterpret_cast(w) = freeLists[bucket]; + freeLists[bucket] = w; + FREE_DTOA_LOCK(0); + } // Copy b into this BigInt, which must be uninitialized. -void JS::BigInt::initCopy(const BigInt &b) -{ - allocate(b.lgGrossSize); - negative = b.negative; - size = b.size; - std::copy(b.words, b.words+size, words); -} + void BigInt::initCopy(const BigInt &b) + { + allocate(b.lgGrossSize); + negative = b.negative; + size = b.size; + std::copy(b.words, b.words+size, words); + } // Move b into this BigInt. The original words array of this BigInt is recycled // and must be non-nil. After the move b has no value. -void JS::BigInt::move(BigInt &b) -{ - recycle(); - lgGrossSize = b.lgGrossSize; - negative = b.negative; - grossSize = b.grossSize; - size = b.size; - words = b.words; - b.words = 0; -} + void BigInt::move(BigInt &b) + { + recycle(); + lgGrossSize = b.lgGrossSize; + negative = b.negative; + grossSize = b.grossSize; + size = b.size; + words = b.words; + b.words = 0; + } -// Change this BigInt's lgGrossSize to the given value without affecting the BigInt value -// contained. This BigInt must currently have a value that will fit in the new lgGrossSize. -void JS::BigInt::setLgGrossSize(uint lgGrossSize) -{ - ASSERT(words); - BigInt b(lgGrossSize); - ASSERT(size <= b.grossSize); - std::copy(words, words+size, b.words); - move(b); -} +// Change this BigInt's lgGrossSize to the given value without affecting the +// BigInt value contained. This BigInt must currently have a value that will +// fit in the new lgGrossSize. + void BigInt::setLgGrossSize(uint lgGrossSize) + { + ASSERT(words); + BigInt b(lgGrossSize); + ASSERT(size <= b.grossSize); + std::copy(words, words+size, b.words); + move(b); + } // Set the BigInt to the given integer value. // The BigInt must not currently have a value. -void JS::BigInt::init(uint32 i) -{ - ASSERT(!words); - allocate(1); // Allocate two words to allow a little room for growth. - if (i) { - size = 1; - words[0] = i; - } else - size = 0; -} + void BigInt::init(uint32 i) + { + ASSERT(!words); + allocate(1); // Allocate two words to allow a little room for growth. + if (i) { + size = 1; + words[0] = i; + } else + size = 0; + } -// Convert d into the form b*2^e, where b is an odd integer. b is the BigInt returned -// in this, and e is the returned binary exponent. Return the number of significant -// bits in b in bits. d must be finite and nonzero. -void JS::BigInt::init(double d, int32 &e, int32 &bits) -{ - allocate(1); +// Convert d into the form b*2^e, where b is an odd integer. b is the BigInt +// returned in this, and e is the returned binary exponent. Return the number +// of significant bits in b in bits. d must be finite and nonzero. + void BigInt::init(double d, int32 &e, int32 &bits) + { + allocate(1); - uint32 *x = words; - uint32 z = word0(d) & Frac_mask; - word0(d) &= 0x7fffffff; // clear sign bit, which we ignore - int32 de = (int32)(word0(d) >> Exp_shift); + uint32 *x = words; + uint32 z = word0(d) & Frac_mask; + word0(d) &= 0x7fffffff; // clear sign bit, which we ignore + int32 de = (int32)(word0(d) >> Exp_shift); #ifdef Sudden_Underflow - z |= Exp_msk11; + z |= Exp_msk11; #else - if (de) - z |= Exp_msk1; + if (de) + z |= Exp_msk1; #endif - uint32 y = word1(d); - int k; - int i; - if (y) { - if ((k = lo0bits(y)) != 0) { - x[0] = y | z << (32 - k); - z >>= k; + uint32 y = word1(d); + int k; + int i; + if (y) { + if ((k = lo0bits(y)) != 0) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; + i = (x[1] = z) ? 2 : 1; + } else { + ASSERT(z); + k = lo0bits(z); + x[0] = z; + i = 1; + k += 32; } - else - x[0] = y; - i = (x[1] = z) ? 2 : 1; - } else { - ASSERT(z); - k = lo0bits(z); - x[0] = z; - i = 1; - k += 32; - } - size = uint32(i); + size = uint32(i); #ifndef Sudden_Underflow - if (de) { + if (de) { #endif - e = de - Bias - (P-1) + k; - bits = P - k; + e = de - Bias - (P-1) + k; + bits = P - k; #ifndef Sudden_Underflow - } else { - e = de - Bias - (P-1) + 1 + k; - bits = 32*i - hi0bits(x[i-1]); - } + } else { + e = de - Bias - (P-1) + 1 + k; + bits = 32*i - hi0bits(x[i-1]); + } #endif -} + } // Let this = this*m + a. Both a and m must be between 0 and 65535 inclusive. -void JS::BigInt::mulAdd(uint m, uint a) -{ + void BigInt::mulAdd(uint m, uint a) + { #ifdef NATIVE_INT64 - uint64 carry, y; + uint64 carry, y; #else - uint32 carry, y; - uint32 xi, z; + uint32 carry, y; + uint32 xi, z; #endif - ASSERT(m <= 0xFFFF && a <= 0xFFFF); - uint32 sz = size; - uint32 *x = words; - carry = a; - for (uint32 i = 0; i != sz; i++) { + ASSERT(m <= 0xFFFF && a <= 0xFFFF); + uint32 sz = size; + uint32 *x = words; + carry = a; + for (uint32 i = 0; i != sz; i++) { #ifdef NATIVE_INT64 - y = *x * (uint64)m + carry; - carry = y >> 32; - *x++ = (uint32)(y & 0xffffffffUL); + y = *x * (uint64)m + carry; + carry = y >> 32; + *x++ = (uint32)(y & 0xffffffffUL); #else - xi = *x; - y = (xi & 0xffff) * m + carry; - z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); #endif + } + if (carry) { + if (sz >= grossSize) + setLgGrossSize(lgGrossSize+1); + words[sz++] = (uint32)carry; + size = sz; + } } - if (carry) { - if (sz >= grossSize) - setLgGrossSize(lgGrossSize+1); - words[sz++] = (uint32)carry; - size = sz; - } -} // Let this = this*m. -void JS::BigInt::operator*=(const BigInt &m) -{ - const BigInt *a; - const BigInt *b; - if (size >= m.size) { - a = this; - b = &m; - } else { - a = &m; - b = this; - } + void BigInt::operator*=(const BigInt &m) + { + const BigInt *a; + const BigInt *b; + if (size >= m.size) { + a = this; + b = &m; + } else { + a = &m; + b = this; + } - uint k = a->lgGrossSize; - uint32 wa = a->size; - uint32 wb = b->size; - uint32 wc = wa + wb; - if (wc > a->grossSize) - k++; + uint k = a->lgGrossSize; + uint32 wa = a->size; + uint32 wb = b->size; + uint32 wc = wa + wb; + if (wc > a->grossSize) + k++; - BigInt c(k); - uint32 *xc; - uint32 *xce; - for (xc = c.words, xce = xc + wc; xc < xce; xc++) - *xc = 0; - const uint32 *xa = a->words; - const uint32 *xae = xa + wa; - const uint32 *xb = b->words; - const uint32 *xbe = xb + wb; - uint32 *xc0 = c.words; - uint32 y; + BigInt c(k); + uint32 *xc; + uint32 *xce; + for (xc = c.words, xce = xc + wc; xc < xce; xc++) + *xc = 0; + const uint32 *xa = a->words; + const uint32 *xae = xa + wa; + const uint32 *xb = b->words; + const uint32 *xbe = xb + wb; + uint32 *xc0 = c.words; + uint32 y; #ifdef NATIVE_INT64 - for (; xb < xbe; xc0++) { - if ((y = *xb++) != 0) { - const uint32 *x = xa; - xc = xc0; - uint64 carry = 0; - do { - uint64 z = *x++ * (uint64)y + *xc + carry; - carry = z >> 32; - *xc++ = (uint32)(z & 0xffffffffUL); - } while (x < xae); - *xc = (uint32)carry; + for (; xb < xbe; xc0++) { + if ((y = *xb++) != 0) { + const uint32 *x = xa; + xc = xc0; + uint64 carry = 0; + do { + uint64 z = *x++ * (uint64)y + *xc + carry; + carry = z >> 32; + *xc++ = (uint32)(z & 0xffffffffUL); + } while (x < xae); + *xc = (uint32)carry; } } #else - for (; xb < xbe; xb++, xc0++) { - uint32 carry; - uint32 z, z2; - const uint32 *x; - - if ((y = *xb & 0xffff) != 0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } while (x < xae); - *xc = carry; + for (; xb < xbe; xb++, xc0++) { + uint32 carry; + uint32 z, z2; + const uint32 *x; + + if ((y = *xb & 0xffff) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } while (x < xae); + *xc = carry; + } + if ((y = *xb >> 16) != 0) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } while (x < xae); + *xc = z2; + } } - if ((y = *xb >> 16) != 0) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } while (x < xae); - *xc = z2; - } - } #endif - for (xc0 = c.words, xc = xc0 + wc; wc && !*--xc; --wc) ; - c.size = wc; - move(c); -} + for (xc0 = c.words, xc = xc0 + wc; wc && !*--xc; --wc) ; + c.size = wc; + move(c); + } // Let this = this * 2^k. k must be nonnegative. -void JS::BigInt::pow2Mul(int32 k) -{ - ASSERT(k >= 0); + void BigInt::pow2Mul(int32 k) + { + ASSERT(k >= 0); - uint32 n = uint32(k) >> 5; - uint k1 = lgGrossSize; - uint32 n1 = n + size + 1; - uint32 i; - for (i = grossSize; n1 > i; i <<= 1) - k1++; + uint32 n = uint32(k) >> 5; + uint k1 = lgGrossSize; + uint32 n1 = n + size + 1; + uint32 i; + for (i = grossSize; n1 > i; i <<= 1) + k1++; - BigInt b1(k1); - uint32 *x1 = b1.words; - for (i = 0; i < n; i++) - *x1++ = 0; - uint32 *x = words; - uint32 *xe = x + size; - if (k &= 0x1f) { - k1 = uint(32 - k); - uint32 z = 0; - while (x != xe) { - *x1++ = *x << k | z; - z = *x++ >> k1; + BigInt b1(k1); + uint32 *x1 = b1.words; + for (i = 0; i < n; i++) + *x1++ = 0; + uint32 *x = words; + uint32 *xe = x + size; + if (k &= 0x1f) { + k1 = uint(32 - k); + uint32 z = 0; + while (x != xe) { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + if ((*x1 = z) != 0) + ++n1; } - if ((*x1 = z) != 0) - ++n1; + else + while (x != xe) + *x1++ = *x++; + b1.size = n1 - 1; + move(b1); } - else - while (x != xe) - *x1++ = *x++; - b1.size = n1 - 1; - move(b1); -} // 'p5s' points to a linked list of Bigints that are powers of 625. @@ -661,1165 +680,1181 @@ void JS::BigInt::pow2Mul(int32 k) // change to NULL or some other value. Only when the value of // 'p5s' or 'next' is NULL do we need to acquire the lock and add // a new BigInt to the list. -struct PowerOf625 { - PowerOf625 *next; - BigInt b; -}; + struct PowerOf625 { + PowerOf625 *next; + BigInt b; + }; -static PowerOf625 *p5s; + static PowerOf625 *p5s; #ifdef JS_THREADSAFE -static PRLock *p5s_lock; + static PRLock *p5s_lock; #endif // Let this = this * 5^k. k must be nonnegative. -void JS::BigInt::pow5Mul(int32 k) -{ - static const uint p05[3] = {5, 25, 125}; + void BigInt::pow5Mul(int32 k) + { + static const uint p05[3] = {5, 25, 125}; - ASSERT(k >= 0); - int32 i = k & 3; - if (i) - mulAdd(p05[i-1], 0); + ASSERT(k >= 0); + int32 i = k & 3; + if (i) + mulAdd(p05[i-1], 0); - if (!(k >>= 2)) - return; - PowerOf625 *p5 = p5s; - if (!p5) { - auto_ptr p(new PowerOf625); - p->next = 0; - p->b.init(625); -#ifdef JS_THREADSAFE - // We take great care to not call init() and recycle() while holding the lock. - // lock and check again - PR_Lock(p5s_lock); - if (!(p5 = p5s)) { -#endif - // first time - p5 = p.release(); - p5s = p5; -#ifdef JS_THREADSAFE - } - PR_Unlock(p5s_lock); -#endif - } - for (;;) { - if (k & 1) - *this *= p5->b; - if (!(k >>= 1)) - break; - PowerOf625 *p51 = p5->next; - if (!p51) { - auto_ptr p(new PowerOf625); - p->next = 0; - p->b = p5->b; - p->b *= p5->b; + if (!(k >>= 2)) + return; + PowerOf625 *p5 = p5s; + if (!p5) { + auto_ptr p(new PowerOf625); + p->next = 0; + p->b.init(625); #ifdef JS_THREADSAFE + // We take great care to not call init() and recycle() while holding + // the lock. lock and check again PR_Lock(p5s_lock); - if (!(p51 = p5->next)) { + if (!(p5 = p5s)) { #endif - p51 = p.release(); - p5->next = p51; + // first time + p5 = p.release(); + p5s = p5; #ifdef JS_THREADSAFE } PR_Unlock(p5s_lock); #endif } - p5 = p51; - } -} - - -// Return -1, 0, or 1 depending on whether thisb, respectively. -int JS::BigInt::cmp(const BigInt &b) const -{ - uint32 i = size; - uint32 j = b.size; -#ifdef DEBUG - if (i > 1 && !words[i-1]) - NOT_REACHED("cmp called with words[size-1] == 0"); - if (j > 1 && !b.words[j-1]) - NOT_REACHED("cmp called with b.words[b.size-1] == 0"); + for (;;) { + if (k & 1) + *this *= p5->b; + if (!(k >>= 1)) + break; + PowerOf625 *p51 = p5->next; + if (!p51) { + auto_ptr p(new PowerOf625); + p->next = 0; + p->b = p5->b; + p->b *= p5->b; +#ifdef JS_THREADSAFE + PR_Lock(p5s_lock); + if (!(p51 = p5->next)) { #endif - if (i != j) - return inext = p51; +#ifdef JS_THREADSAFE + } + PR_Unlock(p5s_lock); +#endif + } + p5 = p51; + } + } + + +// Return -1, 0, or 1 depending on whether thisb, +// respectively. + int BigInt::cmp(const BigInt &b) const + { + uint32 i = size; + uint32 j = b.size; +#ifdef DEBUG + if (i > 1 && !words[i-1]) + NOT_REACHED("cmp called with words[size-1] == 0"); + if (j > 1 && !b.words[j-1]) + NOT_REACHED("cmp called with b.words[b.size-1] == 0"); +#endif + if (i != j) + return ilgGrossSize); - negative = i < 0; - uint32 wa = a->size; - const uint32 *xa = a->words; - const uint32 *xae = xa + wa; - const uint32 *xb = b->words; - const uint32 *xbe = xb + b->size; - uint32 *xc = words; + int i = m.cmp(n); + if (!i) + init(0); + else { + const BigInt *a; + const BigInt *b; + if (i < 0) { + a = &n; + b = &m; + } else { + a = &m; + b = &n; + } + allocate(a->lgGrossSize); + negative = i < 0; + uint32 wa = a->size; + const uint32 *xa = a->words; + const uint32 *xae = xa + wa; + const uint32 *xb = b->words; + const uint32 *xbe = xb + b->size; + uint32 *xc = words; #ifdef NATIVE_INT64 - uint64 borrow = 0; - uint64 y; - while (xb < xbe) { - y = (uint64)*xa++ - *xb++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (uint32)(y & 0xffffffffUL); - } - while (xa < xae) { - y = *xa++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (uint32)(y & 0xffffffffUL); - } + uint64 borrow = 0; + uint64 y; + while (xb < xbe) { + y = (uint64)*xa++ - *xb++ - borrow; + borrow = y >> 32 & 1UL; + *xc++ = (uint32)(y & 0xffffffffUL); + } + while (xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & 1UL; + *xc++ = (uint32)(y & 0xffffffffUL); + } #else - uint32 borrow = 0; - uint32 y; - uint32 z; - while (xb < xbe) { - y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while (xa < xae) { - y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } + uint32 borrow = 0; + uint32 y; + uint32 z; + while (xb < xbe) { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while (xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } #endif - while (!*--xc) - wa--; - size = wa; + while (!*--xc) + wa--; + size = wa; + } } -} // Return floor(this/2^k) and set this to be the remainder. // The returned quotient must be less than 2^32. -uint32 JS::BigInt::quoRem2(int32 k) -{ - int32 n = k >> 5; - k &= 0x1F; - uint32 mask = (1u<> 5; + k &= 0x1F; + uint32 mask = (1u<> k; - *bxe &= mask; - if (w == 2) { - ASSERT(!(bxe[1] & ~mask)); - if (k) - result |= bxe[1] << (32 - k); + int32 w = int32(size) - n; + if (w <= 0) + return 0; + ASSERT(w <= 2); + uint32 *bx = words; + uint32 *bxe = bx + n; + uint32 result = *bxe >> k; + *bxe &= mask; + if (w == 2) { + ASSERT(!(bxe[1] & ~mask)); + if (k) + result |= bxe[1] << (32 - k); + } + n++; + while (!*bxe && bxe != bx) { + n--; + bxe--; + } + size = uint32(n); + return result; } - n++; - while (!*bxe && bxe != bx) { - n--; - bxe--; - } - size = uint32(n); - return result; -} -// Return floor(this/S) and set this to be the remainder. As added restrictions, this must not have -// more words than S, the most significant word of S must not start with a 1 bit, and the -// returned quotient must be less than 36. -int32 JS::BigInt::quoRem(const BigInt &S) -{ +// Return floor(this/S) and set this to be the remainder. As added restrictions, +// this must not have more words than S, the most significant word of S must not +// start with a 1 bit, and the returned quotient must be less than 36. + int32 BigInt::quoRem(const BigInt &S) + { #ifdef NATIVE_INT64 - uint64 borrow, carry, y, ys; + uint64 borrow, carry, y, ys; #else - uint32 borrow, carry, y, ys; - uint32 si, z, zs; + uint32 borrow, carry, y, ys; + uint32 si, z, zs; #endif - uint32 n = S.size; - ASSERT(size <= n && n); - if (size < n) - return 0; - const uint32 *sx = S.words; - const uint32 *sxe = sx + --n; - uint32 *bx = words; - uint32 *bxe = bx + n; - ASSERT(*sxe <= 0x7FFFFFFF); - uint32 q = *bxe / (*sxe + 1); // ensure q <= true quotient - ASSERT(q < 36); - if (q) { - borrow = 0; - carry = 0; - do { + uint32 n = S.size; + ASSERT(size <= n && n); + if (size < n) + return 0; + const uint32 *sx = S.words; + const uint32 *sxe = sx + --n; + uint32 *bx = words; + uint32 *bxe = bx + n; + ASSERT(*sxe <= 0x7FFFFFFF); + uint32 q = *bxe / (*sxe + 1); // ensure q <= true quotient + ASSERT(q < 36); + if (q) { + borrow = 0; + carry = 0; + do { #ifdef NATIVE_INT64 - ys = *sx++ * (uint64)q + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (uint32)(y & 0xffffffffUL); + ys = *sx++ * (uint64)q + carry; + carry = ys >> 32; + y = *bx - (ys & 0xffffffffUL) - borrow; + borrow = y >> 32 & 1UL; + *bx++ = (uint32)(y & 0xffffffffUL); #else - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); #endif - } while (sx <= sxe); - if (!*bxe) { + } while (sx <= sxe); + if (!*bxe) { + bx = words; + while (--bxe > bx && !*bxe) + --n; + size = n; + } + } + if (cmp(S) >= 0) { + q++; + borrow = 0; + carry = 0; bx = words; - while (--bxe > bx && !*bxe) - --n; - size = n; - } - } - if (cmp(S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = words; - sx = S.words; - do { + sx = S.words; + do { #ifdef NATIVE_INT64 - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (uint32)(y & 0xffffffffUL); + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & 0xffffffffUL) - borrow; + borrow = y >> 32 & 1UL; + *bx++ = (uint32)(y & 0xffffffffUL); #else - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); #endif - } while (sx <= sxe); - bx = words; - bxe = bx + n; - if (!*bxe) { - while (--bxe > bx && !*bxe) - --n; - size = n; + } while (sx <= sxe); + bx = words; + bxe = bx + n; + if (!*bxe) { + while (--bxe > bx && !*bxe) + --n; + size = n; + } } + return int32(q); } - return int32(q); -} -// Let this = floor(this / divisor), and return the remainder. this must be nonnegative. -// divisor must be between 1 and 65536. -uint32 JS::BigInt::divRem(uint32 divisor) -{ - uint32 n = size; - uint32 remainder = 0; +// Let this = floor(this / divisor), and return the remainder. this must be +// nonnegative. divisor must be between 1 and 65536. + uint32 BigInt::divRem(uint32 divisor) + { + uint32 n = size; + uint32 remainder = 0; - ASSERT(divisor > 0 && divisor <= 65536); + ASSERT(divisor > 0 && divisor <= 65536); - if (!n) - return 0; // this is zero - uint32 *bx = words; - uint32 *bp = bx + n; - do { - uint32 a = *--bp; - uint32 dividend = remainder << 16 | a >> 16; - uint32 quotientHi = dividend / divisor; - uint32 quotientLo; + if (!n) + return 0; // this is zero + uint32 *bx = words; + uint32 *bp = bx + n; + do { + uint32 a = *--bp; + uint32 dividend = remainder << 16 | a >> 16; + uint32 quotientHi = dividend / divisor; + uint32 quotientLo; - remainder = dividend - quotientHi*divisor; - ASSERT(quotientHi <= 0xFFFF && remainder < divisor); - dividend = remainder << 16 | (a & 0xFFFF); - quotientLo = dividend / divisor; - remainder = dividend - quotientLo*divisor; - ASSERT(quotientLo <= 0xFFFF && remainder < divisor); - *bp = quotientHi << 16 | quotientLo; - } while (bp != bx); - // Decrease the size of the number if its most significant word is now zero. - if (bx[n-1] == 0) - size--; - return remainder; -} - - -double JS::BigInt::b2d(int32 &e) const -{ - double d; - - const uint32 *xa0 = words; - const uint32 *xa = xa0 + size; - ASSERT(size); - uint32 y = *--xa; - ASSERT(y); - int k = hi0bits(y); - e = 32 - k; - if (k < Ebits) { - word0(d) = Exp_1 | y >> (Ebits - k); - uint32 w = xa > xa0 ? *--xa : 0; - word1(d) = y << (32-Ebits + k) | w >> (Ebits - k); - } else { - uint32 z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - word0(d) = Exp_1 | y << k | z >> (32 - k); - y = xa > xa0 ? *--xa : 0; - word1(d) = z << k | y >> (32 - k); - } - else { - word0(d) = Exp_1 | y; - word1(d) = z; - } + remainder = dividend - quotientHi*divisor; + ASSERT(quotientHi <= 0xFFFF && remainder < divisor); + dividend = remainder << 16 | (a & 0xFFFF); + quotientLo = dividend / divisor; + remainder = dividend - quotientLo*divisor; + ASSERT(quotientLo <= 0xFFFF && remainder < divisor); + *bp = quotientHi << 16 | quotientLo; + } while (bp != bx); + // Decrease the size of the number if its most significant word is now + // zero. + if (bx[n-1] == 0) + size--; + return remainder; } - return d; -} -double JS::BigInt::ratio(const BigInt &denominator) const -{ - int32 ka, kb; + double BigInt::b2d(int32 &e) const + { + double d; - double da = b2d(ka); - double db = denominator.b2d(kb); - int32 k = ka - kb + 32*int32(size - denominator.size); - if (k > 0) - word0(da) += k*Exp_msk1; - else - word0(db) -= k*Exp_msk1; - return da / db; -} + const uint32 *xa0 = words; + const uint32 *xa = xa0 + size; + ASSERT(size); + uint32 y = *--xa; + ASSERT(y); + int k = hi0bits(y); + e = 32 - k; + if (k < Ebits) { + word0(d) = Exp_1 | y >> (Ebits - k); + uint32 w = xa > xa0 ? *--xa : 0; + word1(d) = y << (32-Ebits + k) | w >> (Ebits - k); + } else { + uint32 z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + word0(d) = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + word1(d) = z << k | y >> (32 - k); + } + else { + word0(d) = Exp_1 | y; + word1(d) = z; + } + } + return d; + } -void JS::BigInt::s2b(const char *s, int32 nd0, int32 nd, uint32 y9) -{ - int32 i; - int32 x, y; + double BigInt::ratio(const BigInt &denominator) const + { + int32 ka, kb; - x = (nd + 8) / 9; - uint k = 0; - for (y = 1; x > y; y <<= 1, k++) ; - ASSERT(!words); - allocate(k); - words[0] = y9; - size = 1; + double da = b2d(ka); + double db = denominator.b2d(kb); + int32 k = ka - kb + 32*int32(size - denominator.size); + if (k > 0) + word0(da) += k*Exp_msk1; + else + word0(db) -= k*Exp_msk1; + return da / db; + } - i = 9; - if (9 < nd0) { - s += 9; - do mulAdd(10, uint(*s++ - '0')); - while (++i < nd0); - s++; - } else - s += 10; - for (; i < nd; i++) - mulAdd(10, uint(*s++ - '0')); -} + + void BigInt::s2b(const char *s, int32 nd0, int32 nd, uint32 y9) + { + int32 i; + int32 x, y; + + x = (nd + 8) / 9; + uint k = 0; + for (y = 1; x > y; y <<= 1, k++) ; + ASSERT(!words); + allocate(k); + words[0] = y9; + size = 1; + + i = 9; + if (9 < nd0) { + s += 9; + do mulAdd(10, uint(*s++ - '0')); + while (++i < nd0); + s++; + } else + s += 10; + for (; i < nd; i++) + mulAdd(10, uint(*s++ - '0')); + } -static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -}; + static const double tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 + }; -static const double bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256}; -static const double tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128, + static const double bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256}; + static const double tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128, #ifdef Avoid_Underflow - 9007199254740992.e-256 + 9007199254740992.e-256 #else - 1e-256 + 1e-256 #endif - }; + }; // The factor of 2^53 in tinytens[4] helps us avoid setting the underflow // flag unnecessarily. It leads to a song and dance at the end of strToDouble. -const int32 Scale_Bit = 0x10; -const int n_bigtens = 5; + const int32 Scale_Bit = 0x10; + const int n_bigtens = 5; #ifdef JS_THREADSAFE -static bool initialized = false; + static bool initialized = false; // hacked replica of nspr _PR_InitDtoa -static void InitDtoa(void) -{ - freelist_lock = PR_NewLock(); + static void InitDtoa(void) + { + freelist_lock = PR_NewLock(); p5s_lock = PR_NewLock(); - initialized = true; -} + initialized = true; + } #endif -// Return as a double-precision floating-point number the value represented by the character -// string str. The string is scanned up to the first unrecognized character. The character -// sequences 'Infinity', '+Infinity', '-Infinity', and 'NaN' are also recognized. +// Return as a double-precision floating-point number the value represented by +// the character string str. The string is scanned up to the first unrecognized +// character. The character sequences 'Infinity', '+Infinity', '-Infinity', and +// 'NaN' are also recognized. // Return a pointer to the character terminating the scan in numEnd. // If no number can be formed, set numEnd to str and return zero. -double JS::strToDouble(const char *str, const char *&numEnd) -{ - int32 scale; - int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0; - const char *s, *s0, *s1; - double aadj, aadj1, adj, rv, rv0; - int32 L; - uint32 y, z; + double strToDouble(const char *str, const char *&numEnd) + { + int32 scale; + int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0; + const char *s, *s0, *s1; + double aadj, aadj1, adj, rv, rv0; + int32 L; + uint32 y, z; #ifdef JS_THREADSAFE - if (!initialized) InitDtoa(); + if (!initialized) InitDtoa(); #endif - nz0 = nz = 0; - bool negative = false; - bool haveSign = false; - rv = 0.; - for (s = str;; s++) - switch (*s) { - case '-': - negative = true; - // no break - case '+': - haveSign = true; - if (*++s) - goto break2; - // no break - case 0: - s = str; - goto ret; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - switch (*s) { - case '0': - nz0 = 1; - while (*++s == '0') ; - if (!*s) - goto ret; - break; - case 'I': - if (!STD::strncmp(s+1, "nfinity", 7)) { - rv = positiveInfinity; - s += 8; - goto ret; - } - break; - case 'N': - if (!haveSign && !STD::strncmp(s+1, "aN", 2)) { - rv = nan; - s += 3; - goto ret; - } - } - s0 = s; - y = z = 0; - for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; - if (c == '.') { - c = *++s; - if (!nd) { - for (; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; + nz0 = nz = 0; + bool negative = false; + bool haveSign = false; + rv = 0.; + for (s = str;; s++) + switch (*s) { + case '-': + negative = true; + // no break + case '+': + haveSign = true; + if (*++s) + goto break2; + // no break + case 0: + s = str; + goto ret; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; } - goto dig_done; - } - for (; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for (i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - } - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - s = str; - goto ret; - } - str = s; - esign = 0; - switch (c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while (c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while ((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - // Avoid confusion from exponents so large that e might overflow. - e = 19999; // safe for 16 bit ints - else - e = (int32)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = str; - } - if (!nd) { - if (!nz && !nz0) { - s = str; - } - goto ret; - } - e1 = e -= nf; - - // Now we have nd0 digits, starting at s0, followed by a - // decimal point, followed by nd-nd0 digits. The number we're - // after is the integer represented by those digits times 10**e - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - rv = y; - if (k > 9) - rv = tens[k - 9] * rv + z; - if (nd <= DBL_DIG && FLT_ROUNDS == 1) { - if (!e) - goto ret; - if (e > 0) { - if (e <= Ten_pmax) { - rv *= tens[e]; - goto ret; - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - // A fancier test would sometimes let us do this for larger i values. - e -= i; - rv *= tens[i]; - rv *= tens[e]; - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - rv /= tens[-e]; - goto ret; - } -#endif - } - e1 += nd - k; - - scale = 0; - - // Get starting approximation = rv * 10**e1 - - if (e1 > 0) { - if ((i = e1 & 15) != 0) - rv *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - // Return infinity. - rv = positiveInfinity; - goto ret; - } - e1 >>= 4; - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= bigtens[j]; - // The last multiplication could overflow. - word0(rv) -= P*Exp_msk1; - rv *= bigtens[j]; - if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - // set to largest number - // (Can't trust DBL_MAX) - word0(rv) = Big0; - word1(rv) = Big1; - } - else - word0(rv) += P*Exp_msk1; - } - } - else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15) != 0) - rv /= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - if (e1 >= 1 << n_bigtens) - goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) - scale = P; - for (j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - rv *= tinytens[j]; - if (scale && (j = P + 1 - int32((word0(rv) & Exp_mask) >> Exp_shift)) > 0) { - // scaled rv is denormal; zap j low bits - if (j >= 32) { - word1(rv) = 0; - word0(rv) &= 0xffffffff << (j-32); - if (!word0(rv)) - word0(rv) = 1; - } - else - word1(rv) &= 0xffffffff << j; - } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= tinytens[j]; - // The last multiplication could underflow. - rv0 = rv; - rv *= tinytens[j]; - if (!rv) { - rv = 2.*rv0; - rv *= tinytens[j]; -#endif - if (!rv) { - undfl: - rv = 0.; + break2: + switch (*s) { + case '0': + nz0 = 1; + while (*++s == '0') ; + if (!*s) + goto ret; + break; + case 'I': + if (!STD::strncmp(s+1, "nfinity", 7)) { + rv = positiveInfinity; + s += 8; goto ret; } -#ifndef Avoid_Underflow - word0(rv) = Tiny0; - word1(rv) = Tiny1; - // The refinement below will clean this approximation up. + break; + case 'N': + if (!haveSign && !STD::strncmp(s+1, "aN", 2)) { + rv = nan; + s += 3; + goto ret; + } + } + s0 = s; + y = z = 0; + for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + if (c == '.') { + c = *++s; + if (!nd) { + for (; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for (; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for (i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + s = str; + goto ret; + } + str = s; + esign = 0; + switch (c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while (c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while ((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + // Avoid confusion from exponents so large that e might + // overflow. + e = 19999; // safe for 16 bit ints + else + e = (int32)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = str; + } + if (!nd) { + if (!nz && !nz0) { + s = str; + } + goto ret; + } + e1 = e -= nf; + + // Now we have nd0 digits, starting at s0, followed by a + // decimal point, followed by nd-nd0 digits. The number we're + // after is the integer represented by those digits times 10**e + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + rv = y; + if (k > 9) + rv = tens[k - 9] * rv + z; + if (nd <= DBL_DIG && FLT_ROUNDS == 1) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { + rv *= tens[e]; + goto ret; + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + // A fancier test would sometimes let us do this for larger + // i values. + e -= i; + rv *= tens[i]; + rv *= tens[e]; + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { + rv /= tens[-e]; + goto ret; } #endif } - } + e1 += nd - k; - // Now the hard part -- adjusting rv to the correct value. + scale = 0; - // Put digits into bd: true value = bd * 10^e - { - BigInt bd0; - bd0.s2b(s0, nd0, nd, y); + // Get starting approximation = rv * 10**e1 - for (;;) { - BigInt bs; + if (e1 > 0) { + if ((i = e1 & 15) != 0) + rv *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: + // Return infinity. + rv = positiveInfinity; + goto ret; + } + e1 >>= 4; + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= bigtens[j]; + // The last multiplication could overflow. + word0(rv) -= P*Exp_msk1; + rv *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + // set to largest number + // (Can't trust DBL_MAX) + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15) != 0) + rv /= tens[i]; + if (e1 &= ~15) { + e1 >>= 4; + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = P; + for (j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + rv *= tinytens[j]; + if (scale && (j = P + 1 - int32((word0(rv) & Exp_mask) >> + Exp_shift)) > 0) { + // scaled rv is denormal; zap j low bits + if (j >= 32) { + word1(rv) = 0; + word0(rv) &= 0xffffffff << (j-32); + if (!word0(rv)) + word0(rv) = 1; + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= tinytens[j]; + // The last multiplication could underflow. + rv0 = rv; + rv *= tinytens[j]; + if (!rv) { + rv = 2.*rv0; + rv *= tinytens[j]; +#endif + if (!rv) { + undfl: + rv = 0.; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + // The refinement below will clean this approximation up. + } +#endif + } + } - BigInt bd = bd0; - BigInt bb; - bb.init(rv, bbe, bbbits); // rv = bb * 2^bbe - bs.init(1); + // Now the hard part -- adjusting rv to the correct value. + // Put digits into bd: true value = bd * 10^e + { + BigInt bd0; + bd0.s2b(s0, nd0, nd, y); - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; + for (;;) { + BigInt bs; + + BigInt bd = bd0; + BigInt bb; + bb.init(rv, bbe, bbbits); // rv = bb * 2^bbe + bs.init(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; #ifdef Sudden_Underflow - j = P + 1 - bbbits; + j = P + 1 - bbbits; #else #ifdef Avoid_Underflow - j = bbe - scale; + j = bbe - scale; #else - j = bbe; + j = bbe; #endif - i = j + bbbits - 1; // logb(rv) - if (i < Emin) // denormal - j += P - Emin; - else - j = P + 1 - bbbits; + i = j + bbbits - 1; // logb(rv) + if (i < Emin) // denormal + j += P - Emin; + else + j = P + 1 - bbbits; #endif - bb2 += j; - bd2 += j; + bb2 += j; + bd2 += j; #ifdef Avoid_Underflow - bd2 += scale; + bd2 += scale; #endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs.pow5Mul(bb5); - bb *= bs; - } - if (bb2 > 0) - bb.pow2Mul(bb2); - if (bd5 > 0) - bd.pow5Mul(bd5); - if (bd2 > 0) - bd.pow2Mul(bd2); - if (bs2 > 0) - bs.pow2Mul(bs2); + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs.pow5Mul(bb5); + bb *= bs; + } + if (bb2 > 0) + bb.pow2Mul(bb2); + if (bd5 > 0) + bd.pow5Mul(bd5); + if (bd2 > 0) + bd.pow2Mul(bd2); + if (bs2 > 0) + bs.pow2Mul(bs2); - BigInt delta; - delta.initDiff(bb, bd); - dsign = delta.negative; - delta.negative = false; - i = delta.cmp(bs); - if (i < 0) { - // Error is less than half an ulp -- check for special case of mantissa a power of two. - if (dsign || word1(rv) || word0(rv) & Bndry_mask + BigInt delta; + delta.initDiff(bb, bd); + dsign = delta.negative; + delta.negative = false; + i = delta.cmp(bs); + if (i < 0) { + // Error is less than half an ulp -- check for special case + // of mantissa a power of two. + if (dsign || word1(rv) || word0(rv) & Bndry_mask #ifdef Avoid_Underflow - || (word0(rv) & Exp_mask) <= Exp_msk1 + P*Exp_msk1 + || (word0(rv) & Exp_mask) <= Exp_msk1 + P*Exp_msk1 #else - || (word0(rv) & Exp_mask) <= Exp_msk1 + || (word0(rv) & Exp_mask) <= Exp_msk1 #endif - ) { + ) { #ifdef Avoid_Underflow - if (delta.isZero()) - dsign = 2; + if (delta.isZero()) + dsign = 2; #endif - break; - } - delta.pow2Mul(Log2P); - if (delta.cmp(bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - // exactly half-way between - if (dsign) { - if ((word0(rv) & Bndry_mask1) == Bndry_mask1 - && word1(rv) == 0xffffffff) { - //boundary case -- increment exponent - word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1; - word1(rv) = 0; + break; + } + delta.pow2Mul(Log2P); + if (delta.cmp(bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + // exactly half-way between + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == 0xffffffff) { + //boundary case -- increment exponent + word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1; + word1(rv) = 0; #ifdef Avoid_Underflow - dsign = 0; + dsign = 0; #endif - break; - } - } - else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { #ifdef Avoid_Underflow - dsign = 2; + dsign = 2; #endif - drop_down: - // boundary case -- decrement exponent + drop_down: + // boundary case -- decrement exponent #ifdef Sudden_Underflow - L = word0(rv) & Exp_mask; - if (L <= Exp_msk1) - goto undfl; - L -= Exp_msk1; + L = word0(rv) & Exp_mask; + if (L <= Exp_msk1) + goto undfl; + L -= Exp_msk1; #else - L = int32((word0(rv) & Exp_mask) - Exp_msk1); + L = int32((word0(rv) & Exp_mask) - Exp_msk1); #endif - word0(rv) = uint32(L) | Bndry_mask1; - word1(rv) = 0xffffffff; - break; - } + word0(rv) = uint32(L) | Bndry_mask1; + word1(rv) = 0xffffffff; + break; + } #ifndef ROUND_BIASED - if (!(word1(rv) & LSB)) - break; + if (!(word1(rv) & LSB)) + break; #endif - if (dsign) - rv += ulp(rv); + if (dsign) + rv += ulp(rv); #ifndef ROUND_BIASED - else { - rv -= ulp(rv); + else { + rv -= ulp(rv); #ifndef Sudden_Underflow - if (!rv) - goto undfl; + if (!rv) + goto undfl; #endif - } + } #ifdef Avoid_Underflow - dsign = 1 - dsign; + dsign = 1 - dsign; #endif #endif - break; - } - if ((aadj = delta.ratio(bs)) <= 2.) { - if (dsign) - aadj = aadj1 = 1.; - else if (word1(rv) || word0(rv) & Bndry_mask) { + break; + } + if ((aadj = delta.ratio(bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { #ifndef Sudden_Underflow - if (word1(rv) == Tiny1 && !word0(rv)) - goto undfl; + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; #endif - aadj = 1.; - aadj1 = -1.; - } - else { - // special case -- power of FLT_RADIX to be - // rounded down... + aadj = 1.; + aadj1 = -1.; + } + else { + // special case -- power of FLT_RADIX to be + // rounded down... - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } - else { - aadj *= 0.5; - aadj1 = dsign ? aadj : -aadj; + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS - switch (FLT_ROUNDS) { - case 2: // towards +infinity - aadj1 -= 0.5; - break; - case 0: // towards 0 - case 3: // towards -infinity - aadj1 += 0.5; - } + switch (FLT_ROUNDS) { + case 2: // towards +infinity + aadj1 -= 0.5; + break; + case 0: // towards 0 + case 3: // towards -infinity + aadj1 += 0.5; + } #else - if (FLT_ROUNDS == 0) - aadj1 += 0.5; + if (FLT_ROUNDS == 0) + aadj1 += 0.5; #endif - } - y = word0(rv) & Exp_mask; + } + y = word0(rv) & Exp_mask; - // Check for overflow + // Check for overflow - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - rv0 = rv; - word0(rv) -= P*Exp_msk1; - adj = aadj1 * ulp(rv); - rv += adj; - if ((word0(rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (word0(rv0) == Big0 && word1(rv0) == Big1) - goto ovfl; - word0(rv) = Big0; - word1(rv) = Big1; - continue; - } - else - word0(rv) += P*Exp_msk1; - } - else { + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + rv0 = rv; + word0(rv) -= P*Exp_msk1; + adj = aadj1 * ulp(rv); + rv += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + continue; + } + else + word0(rv) += P*Exp_msk1; + } + else { #ifdef Sudden_Underflow - if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { - rv0 = rv; - word0(rv) += P*Exp_msk1; - adj = aadj1 * ulp(rv); - rv += adj; - if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { - if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) - goto undfl; - word0(rv) = Tiny0; - word1(rv) = Tiny1; - continue; - } else - word0(rv) -= P*Exp_msk1; - } else { - adj = aadj1 * ulp(rv); - rv += adj; - } + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + rv0 = rv; + word0(rv) += P*Exp_msk1; + adj = aadj1 * ulp(rv); + rv += adj; + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + continue; + } else + word0(rv) -= P*Exp_msk1; + } else { + adj = aadj1 * ulp(rv); + rv += adj; + } #else - // Compute adj so that the IEEE rounding rules will - // correctly round rv + adj in some half-way cases. - // If rv * ulp(rv) is denormalized (i.e., - // y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - // trouble from bits lost to denormalization; - // example: 1.2e-307 . + // Compute adj so that the IEEE rounding rules will + // correctly round rv + adj in some half-way cases. + // If rv * ulp(rv) is denormalized (i.e., + // y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + // trouble from bits lost to denormalization; + // example: 1.2e-307 . #ifdef Avoid_Underflow - if (y <= P*Exp_msk1 && aadj > 1.) + if (y <= P*Exp_msk1 && aadj > 1.) #else - if (y <= (P-1)*Exp_msk1 && aadj > 1.) + if (y <= (P-1)*Exp_msk1 && aadj > 1.) #endif - { - aadj1 = (double)(int32)(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } + { + aadj1 = (double)(int32)(aadj + 0.5); + if (!dsign) + aadj1 = -aadj1; + } #ifdef Avoid_Underflow - if (scale && y <= P*Exp_msk1) - word0(aadj1) += (P+1)*Exp_msk1 - y; + if (scale && y <= P*Exp_msk1) + word0(aadj1) += (P+1)*Exp_msk1 - y; #endif - adj = aadj1 * ulp(rv); - rv += adj; + adj = aadj1 * ulp(rv); + rv += adj; #endif - } - z = word0(rv) & Exp_mask; + } + z = word0(rv) & Exp_mask; #ifdef Avoid_Underflow - if (!scale) + if (!scale) #endif - if (y == z) { - // Can we stop now? - L = (int32)aadj; - aadj -= L; - // The tolerances below are conservative. - if (dsign || word1(rv) || word0(rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; - } - } + if (y == z) { + // Can we stop now? + L = (int32)aadj; + aadj -= L; + // The tolerances below are conservative. + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + } #ifdef Avoid_Underflow - if (scale) { - word0(rv0) = Exp_1 - P*Exp_msk1; - word1(rv0) = 0; - if ((word0(rv) & Exp_mask) <= P*Exp_msk1 - && word1(rv) & 1 - && dsign != 2) { - if (dsign) { + if (scale) { + word0(rv0) = Exp_1 - P*Exp_msk1; + word1(rv0) = 0; + if ((word0(rv) & Exp_mask) <= P*Exp_msk1 + && word1(rv) & 1 + && dsign != 2) { + if (dsign) { #ifdef Sudden_Underflow - // rv will be 0, but this would give the - // right result if only rv *= rv0 worked. - word0(rv) += P*Exp_msk1; - word0(rv0) = Exp_1 - 2*P*Exp_msk1; + // rv will be 0, but this would give the + // right result if only rv *= rv0 worked. + word0(rv) += P*Exp_msk1; + word0(rv0) = Exp_1 - 2*P*Exp_msk1; #endif - rv += ulp(rv); - } - else - word1(rv) &= ~1; - } - rv *= rv0; - } + rv += ulp(rv); + } + else + word1(rv) &= ~1; + } + rv *= rv0; + } #endif // Avoid_Underflow - } - ret: - numEnd = s; - return negative ? -rv : rv; -} - - -// A version of strToDouble that takes a char16 string that begins at str and ends just -// before strEnd. The char16 string does not have to be null-terminated. -// Leading Unicode whitespace is skipped. -double JS::stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd) -{ - const char16 *str1 = skipWhiteSpace(str, strEnd); - - CharAutoPtr cstr(new char[strEnd - str1 + 1]); - char *q = cstr.get(); - for (const char16 *p = str1; p != strEnd; p++) { - char16 ch = *p; - if (uint16(ch) >> 8) - break; - *q++ = char(ch); + } + ret: + numEnd = s; + return negative ? -rv : rv; } - *q = '\0'; - const char *estr; - double value = strToDouble(cstr.get(), estr); - ptrdiff_t i = estr - cstr.get(); - numEnd = i ? str1 + i : str; - return value; -} + +// A version of strToDouble that takes a char16 string that begins at str and +// ends just before strEnd. The char16 string does not have to be +// null-terminated. Leading Unicode whitespace is skipped. + double stringToDouble(const char16 *str, const char16 *strEnd, + const char16 *&numEnd) + { + const char16 *str1 = skipWhiteSpace(str, strEnd); + + CharAutoPtr cstr(new char[strEnd - str1 + 1]); + char *q = cstr.get(); + for (const char16 *p = str1; p != strEnd; p++) { + char16 ch = *p; + if (uint16(ch) >> 8) + break; + *q++ = char(ch); + } + *q = '\0'; + + const char *estr; + double value = strToDouble(cstr.get(), estr); + ptrdiff_t i = estr - cstr.get(); + numEnd = i ? str1 + i : str; + return value; + } -class BinaryDigitReader -{ - uint base; // Base of number; must be a power of 2 - uint digit; // Current digit value in radix given by base - uint digitMask; // Mask to extract the next bit from digit - const char16 *digits; // Pointer to the remaining digits - const char16 *digitsEnd; // Pointer to first non-digit + class BinaryDigitReader + { + uint base; // Base of number; must be a power of 2 + uint digit; // Current digit value in radix given by base + uint digitMask; // Mask to extract the next bit from digit + const char16 *digits; // Pointer to the remaining digits + const char16 *digitsEnd; // Pointer to first non-digit - public: - BinaryDigitReader(uint base, const char16 *digitsBegin, const char16 *digitsEnd): - base(base), digitMask(0), digits(digitsBegin), digitsEnd(digitsEnd) {} - - int next(); -}; + public: + BinaryDigitReader(uint base, const char16 *digitsBegin, + const char16 *digitsEnd) : + base(base), digitMask(0), digits(digitsBegin), + digitsEnd(digitsEnd) {} + + int next(); + }; // Return the next binary digit from the number or -1 if done. -int BinaryDigitReader::next() -{ - if (digitMask == 0) { - if (digits == digitsEnd) - return -1; + int BinaryDigitReader::next() + { + if (digitMask == 0) { + if (digits == digitsEnd) + return -1; - uint c = *digits++; - if ('0' <= c && c <= '9') - digit = c - '0'; - else if ('a' <= c && c <= 'z') - digit = c - 'a' + 10; - else digit = c - 'A' + 10; - digitMask = base >> 1; + uint c = *digits++; + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('a' <= c && c <= 'z') + digit = c - 'a' + 10; + else digit = c - 'A' + 10; + digitMask = base >> 1; + } + int bit = (digit & digitMask) != 0; + digitMask >>= 1; + return bit; } - int bit = (digit & digitMask) != 0; - digitMask >>= 1; - return bit; -} -// Read an integer from a char16 string that begins at str and ends just before strEnd. -// The char16 string does not have to be null-terminated. The integer is returned as a double, -// which is guaranteed to be the closest double number to the given input when base is 10 or a power of 2. +// Read an integer from a char16 string that begins at str and ends just before +// strEnd. The char16 string does not have to be null-terminated. The integer +// is returned as a double, which is guaranteed to be the closest double number +// to the given input when base is 10 or a power of 2. // May experience roundoff errors for very large numbers of a different radix. // Return a pointer to the character just past the integer in numEnd. // If the string does not have a number in it, set numEnd to str and return 0. // Leading Unicode whitespace is skipped. -double JS::stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base) -{ - const char16 *str1 = skipWhiteSpace(str, strEnd); + double stringToInteger(const char16 *str, const char16 *strEnd, + const char16 *&numEnd, uint base) + { + const char16 *str1 = skipWhiteSpace(str, strEnd); - bool negative = (*str1 == '-'); - if (negative || *str1 == '+') - str1++; + bool negative = (*str1 == '-'); + if (negative || *str1 == '+') + str1++; - if ((base == 0 || base == 16) && *str1 == '0' && (str1[1] == 'X' || str1[1] == 'x')) { - // Skip past hex prefix. - base = 16; - str1 += 2; - } - if (base == 0) - base = 10; // Default to decimal. + if ((base == 0 || base == 16) && + *str1 == '0' && (str1[1] == 'X' || str1[1] == 'x')) { + // Skip past hex prefix. + base = 16; + str1 += 2; + } + if (base == 0) + base = 10; // Default to decimal. - // Find some prefix of the string that's a number in the given base. - const char16 *start = str1; // Mark - if string is empty, we return 0. - double value = 0.0; - while (true) { - uint digit; - char16 c = *str1; - if ('0' <= c && c <= '9') - digit = uint(c) - '0'; - else if ('a' <= c && c <= 'z') - digit = uint(c) - 'a' + 10; - else if ('A' <= c && c <= 'Z') - digit = uint(c) - 'A' + 10; - else - break; - if (digit >= base) - break; - value = value*base + digit; - str1++; + // Find some prefix of the string that's a number in the given base. + const char16 *start = str1; // Mark - if string is empty, we return 0. + double value = 0.0; + while (true) { + uint digit; + char16 c = *str1; + if ('0' <= c && c <= '9') + digit = uint(c) - '0'; + else if ('a' <= c && c <= 'z') + digit = uint(c) - 'a' + 10; + else if ('A' <= c && c <= 'Z') + digit = uint(c) - 'A' + 10; + else + break; + if (digit >= base) + break; + value = value*base + digit; + str1++; + } + + if (value >= 9007199254740992.0) { + if (base == 10) { + // If we're accumulating a decimal number and the number is + // >= 2^53, then the result from the repeated multiply-add above + // may be inaccurate. Call stringToDouble to get the correct + // answer. + const char16 *numEnd2; + value = stringToDouble(start, str1, numEnd2); + ASSERT(numEnd2 == str1); + + } else if (base == 2 || base == 4 || base == 8 || base == 16 || + base == 32) { + // The number may also be inaccurate for one of these bases. + // This happens if the addition in value*base + digit causes a + // round-down to an even least significant mantissa bit when the + // first dropped bit is a one. If any of the following digits + // in the number (which haven't been added in yet) are nonzero + // then the correct action would have been to round up instead + // of down. An example of this occurs when reading the number + // 0x1000000000000081, which rounds to 0x1000000000000000 + // instead of 0x1000000000000100. + BinaryDigitReader bdr(base, start, str1); + value = 0.0; + + // Skip leading zeros. + int bit; + do { + bit = bdr.next(); + } while (bit == 0); + + if (bit == 1) { + // Gather the 53 significant bits (including the leading 1) + int bit2; + value = 1.0; + for (int j = 52; j; --j) { + bit = bdr.next(); + if (bit < 0) + goto done; + value = value*2 + bit; + } + // bit2 is the 54th bit (the first dropped from the mantissa) + bit2 = bdr.next(); + if (bit2 >= 0) { + double factor = 2.0; + // sticky is 1 if any bit beyond the 54th is 1 + int sticky = 0; + int bit3; + + while ((bit3 = bdr.next()) >= 0) { + sticky |= bit3; + factor *= 2; + } + value += bit2 & (bit | sticky); + value *= factor; + } + done:; + } + } + } + // We don't worry about inaccurate numbers for any other base. + + if (str1 == start) + numEnd = str; + else { + numEnd = str1; + if (negative) + value = -value; + } + return value; } - if (value >= 9007199254740992.0) { - if (base == 10) { - // If we're accumulating a decimal number and the number is >= 2^53, then - // the result from the repeated multiply-add above may be inaccurate. Call - // stringToDouble to get the correct answer. - const char16 *numEnd2; - value = stringToDouble(start, str1, numEnd2); - ASSERT(numEnd2 == str1); - - } else if (base == 2 || base == 4 || base == 8 || base == 16 || base == 32) { - // The number may also be inaccurate for one of these bases. This - // happens if the addition in value*base + digit causes a round-down - // to an even least significant mantissa bit when the first dropped bit - // is a one. If any of the following digits in the number (which haven't - // been added in yet) are nonzero then the correct action would have - // been to round up instead of down. An example of this occurs when - // reading the number 0x1000000000000081, which rounds to 0x1000000000000000 - // instead of 0x1000000000000100. - BinaryDigitReader bdr(base, start, str1); - value = 0.0; - - // Skip leading zeros. - int bit; - do { - bit = bdr.next(); - } while (bit == 0); - - if (bit == 1) { - // Gather the 53 significant bits (including the leading 1) - int bit2; - value = 1.0; - for (int j = 52; j; --j) { - bit = bdr.next(); - if (bit < 0) - goto done; - value = value*2 + bit; - } - // bit2 is the 54th bit (the first dropped from the mantissa) - bit2 = bdr.next(); - if (bit2 >= 0) { - double factor = 2.0; - int sticky = 0; // sticky is 1 if any bit beyond the 54th is 1 - int bit3; - - while ((bit3 = bdr.next()) >= 0) { - sticky |= bit3; - factor *= 2; - } - value += bit2 & (bit | sticky); - value *= factor; - } - done:; - } - } - } - // We don't worry about inaccurate numbers for any other base. - - if (str1 == start) - numEnd = str; - else { - numEnd = str1; - if (negative) - value = -value; - } - return value; -} - // doubleToAscii for IEEE arithmetic (dmg): convert double to ASCII string. @@ -1864,718 +1899,718 @@ double JS::stringToInteger(const char16 *str, const char16 *strEnd, const char16 // The buffer should be at least 20 bytes for modes 0 and 1. For the other modes, // the buffer's size should be two greater than the maximum number of output characters expected. // Return a pointer to the resulting string's trailing null. -static char *doubleToAscii(double d, int mode, bool biasUp, int ndigits, - int *decpt, bool *negative, char *buf) -{ - /* Arguments ndigits, decpt, negative are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If d is +-Infinity or NaN, - then *decpt is set to 9999. + static char *doubleToAscii(double d, int mode, bool biasUp, int ndigits, + int *decpt, bool *negative, char *buf) + { + /* Arguments ndigits, decpt, negative are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If d is +-Infinity or NaN, + then *decpt is set to 9999. - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4-9 should give the same return values as 2-3, i.e., + 4 <= mode <= 9 ==> same return as mode + 2 + (mode & 1). These modes are mainly for + debugging; often they run slower but sometimes + faster than modes 2-3. + 4,5,8,9 ==> left-to-right digit generation. + 6-9 ==> don't try fast floating-point estimate + (if applicable). - Values of mode other than 0-9 are treated as mode 0. + Values of mode other than 0-9 are treated as mode 0. - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. */ - int32 bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - try_quick; - int32 L; + int32 bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + try_quick; + int32 L; #ifndef Sudden_Underflow - int32 denorm; - uint32 x; + int32 denorm; + uint32 x; #endif - double d2, ds, eps; - char *s; + double d2, ds, eps; + char *s; #ifdef JS_THREADSAFE - if (!initialized) InitDtoa(); + if (!initialized) InitDtoa(); #endif - if (word0(d) & Sign_bit) { - // set negative for everything, including 0's and NaNs - *negative = true; - word0(d) &= ~Sign_bit; // clear sign bit - } - else - *negative = false; + if (word0(d) & Sign_bit) { + // set negative for everything, including 0's and NaNs + *negative = true; + word0(d) &= ~Sign_bit; // clear sign bit + } + else + *negative = false; - if ((word0(d) & Exp_mask) == Exp_mask) { - // Infinity or NaN - *decpt = 9999; - strcpy(buf, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); - return buf[3] ? buf + 8 : buf + 3; - } - if (!d) { - no_digits: - *decpt = 1; - buf[0] = '0'; buf[1] = '\0'; // copy "0" to buffer - return buf + 1; - } + if ((word0(d) & Exp_mask) == Exp_mask) { + // Infinity or NaN + *decpt = 9999; + strcpy(buf, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); + return buf[3] ? buf + 8 : buf + 3; + } + if (!d) { + no_digits: + *decpt = 1; + buf[0] = '0'; buf[1] = '\0'; // copy "0" to buffer + return buf + 1; + } - BigInt b; - b.init(d, be, bbits); + BigInt b; + b.init(d, be, bbits); #ifdef Sudden_Underflow - i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); + i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else - if ((i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { + if ((i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { #endif - d2 = d; - word0(d2) &= Frac_mask1; - word0(d2) |= Exp_11; + d2 = d; + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ - i -= Bias; + i -= Bias; #ifndef Sudden_Underflow - denorm = 0; - } - else { - // d is denormalized - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i); - d2 = x; - word0(d2) -= 31*Exp_msk1; // adjust exponent - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; - } -#endif - // At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. - ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = (int32)ds; - if (ds < 0. && ds != k) - k--; // want k = floor(ds) - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (d < tens[k]) - k--; - k_check = 0; - } - // At this point floor(log10(d)) <= k <= floor(log10(d))+1. - // If k_check is zero, we're guaranteed that k = floor(log10(d)). - j = bbits - i - 1; - // At this point d = b/2^j, where b is an odd integer. - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - // At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer, - // b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. - if (mode < 0 || mode > 9) - mode = 0; - try_quick = 1; - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - ilim = ilim1 = 0; - switch (mode) { - case 0: - case 1: - ilim = ilim1 = -1; - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - // no break - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - // no break - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - // ilim is the maximum number of significant digits we want, based on k and ndigits. - // ilim1 is the maximum number of significant digits we want, based on k and ndigits, - // when it turns out that k was computed too high by one. - s = buf; - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - // Try to get by with floating-point arithmetic. - - i = 0; - d2 = d; - k0 = k; - ilim0 = ilim; - ieps = 2; // conservative - // Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - // prevent overflows - j &= Bletch - 1; - d /= bigtens[n_bigtens-1]; - ieps++; - } - for (; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - d /= ds; - } - else if ((j1 = -k) != 0) { - d *= tens[j1 & 0xf]; - for (j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - d *= bigtens[i]; - } - } - // Check that k was computed correctly. - if (k_check && d < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - d *= 10.; - ieps++; - } - // eps bounds the cumulative error. - eps = ieps*d + 7.; - word0(eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - d -= 5.; - if (d > eps) - goto one_digit; - if (d < -eps) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - // Use Steele & White method of only generating digits needed. - eps = 0.5/tens[ilim-1] - eps; - for (i = 0;;) { - L = (int32)d; - d -= L; - *s++ = char('0' + L); - if (d < eps) - goto ret1; - if (1. - d < eps) - goto bump_up; - if (++i >= ilim) - break; - eps *= 10.; - d *= 10.; - } + denorm = 0; } else { + // d is denormalized + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i); + d2 = x; + word0(d2) -= 31*Exp_msk1; // adjust exponent + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + // At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. + ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int32)ds; + if (ds < 0. && ds != k) + k--; // want k = floor(ds) + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (d < tens[k]) + k--; + k_check = 0; + } + // At this point floor(log10(d)) <= k <= floor(log10(d))+1. + // If k_check is zero, we're guaranteed that k = floor(log10(d)). + j = bbits - i - 1; + // At this point d = b/2^j, where b is an odd integer. + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + // At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer, + // b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. + if (mode < 0 || mode > 9) + mode = 0; + try_quick = 1; + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = 0; + switch (mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + // no break + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + // no break + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + // ilim is the maximum number of significant digits we want, based on k and ndigits. + // ilim1 is the maximum number of significant digits we want, based on k and ndigits, + // when it turns out that k was computed too high by one. + s = buf; + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + // Try to get by with floating-point arithmetic. + + i = 0; + d2 = d; + k0 = k; + ilim0 = ilim; + ieps = 2; // conservative + // Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + // prevent overflows + j &= Bletch - 1; + d /= bigtens[n_bigtens-1]; + ieps++; + } + for (; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + d /= ds; + } + else if ((j1 = -k) != 0) { + d *= tens[j1 & 0xf]; + for (j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + d *= bigtens[i]; + } + } + // Check that k was computed correctly. + if (k_check && d < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + d *= 10.; + ieps++; + } + // eps bounds the cumulative error. + eps = ieps*d + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + d -= 5.; + if (d > eps) + goto one_digit; + if (d < -eps) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + // Use Steele & White method of only generating digits needed. + eps = 0.5/tens[ilim-1] - eps; + for (i = 0;;) { + L = (int32)d; + d -= L; + *s++ = char('0' + L); + if (d < eps) + goto ret1; + if (1. - d < eps) + goto bump_up; + if (++i >= ilim) + break; + eps *= 10.; + d *= 10.; + } + } + else { +#endif + // Generate ilim digits, then fix them up. + eps *= tens[ilim-1]; + for (i = 1;; i++, d *= 10.) { + L = (int32)d; + d -= L; + *s++ = char('0' + L); + if (i == ilim) { + if (d > 0.5 + eps) + goto bump_up; + else if (d < 0.5 - eps) { + while (*--s == '0') ; + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = buf; + d = d2; + k = k0; + ilim = ilim0; + } + + // Do we have a "small" integer? + + if (be >= 0 && k <= Int_max) { + // Yes. + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds)) + goto no_digits; + one_digit: + *s++ = '1'; + k++; + goto ret1; + } + for (i = 1;; i++) { + L = (int32) (d / ds); + d -= L*ds; +#ifdef Check_FLT_ROUNDS + // If FLT_ROUNDS == 2, L will usually be high by 1 + if (d < 0) { + L--; + d += ds; + } #endif - // Generate ilim digits, then fix them up. - eps *= tens[ilim-1]; - for (i = 1;; i++, d *= 10.) { - L = (int32)d; - d -= L; *s++ = char('0' + L); if (i == ilim) { - if (d > 0.5 + eps) - goto bump_up; - else if (d < 0.5 - eps) { - while (*--s == '0') ; - s++; - goto ret1; + d += d; + if ((d > ds) || (d == ds && (L & 1 || biasUp))) { + bump_up: + while (*--s == '9') + if (s == buf) { + k++; + *s = '0'; + break; + } + ++*s++; } break; } + if (!(d *= 10.)) + break; } -#ifndef No_leftright + goto ret1; } -#endif - fast_failed: - s = buf; - d = d2; - k = k0; - ilim = ilim0; - } - // Do we have a "small" integer? + { + m2 = b2; + m5 = b5; + BigInt mLow; // If spec_case is false, assume that mLow == mHigh + BigInt mHigh; - if (be >= 0 && k <= Int_max) { - // Yes. - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds)) - goto no_digits; - one_digit: - *s++ = '1'; - k++; - goto ret1; - } - for (i = 1;; i++) { - L = (int32) (d / ds); - d -= L*ds; -#ifdef Check_FLT_ROUNDS - // If FLT_ROUNDS == 2, L will usually be high by 1 - if (d < 0) { - L--; - d += ds; - } + if (leftright) { + if (mode < 2) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : #endif - *s++ = char('0' + L); - if (i == ilim) { - d += d; - if ((d > ds) || (d == ds && (L & 1 || biasUp))) { - bump_up: - while (*--s == '9') - if (s == buf) { - k++; - *s = '0'; - break; - } - ++*s++; + 1 + P - bbits; + // i is 1 plus the number of trailing zero bits in d's significand. Thus, + // (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. } - break; + else { + j = ilim - 1; + if (m5 >= j) + m5 -= j; + else { + s5 += j -= m5; + b5 += j; + m5 = 0; + } + if ((i = ilim) < 0) { + m2 -= i; + i = 0; + } + // (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. + } + b2 += i; + s2 += i; + mHigh.init(1); + // (mHigh * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or + // input (when mode < 2) significant digit, divided by 10^k. } - if (!(d *= 10.)) - break; + // We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in + // b2, m2, and s2 without changing the equalities. + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + + // Fold b5 into b and m5 into mHigh. + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mHigh.pow5Mul(m5); + b *= mHigh; + } + if ((j = b5 - m5) != 0) + b.pow5Mul(j); + } + else + b.pow5Mul(b5); + } + // Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and + // (mHigh * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. + + BigInt S; + S.init(1); + if (s5 > 0) + S.pow5Mul(s5); + // Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and + // (mHigh * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. + + // Check for special case that d is a normalized power of 2. + bool spec_case = false; + if (mode < 2) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & Exp_mask << 1) +#endif + ) { + // The special case. Here we want to be within a quarter of the last input + // significant digit instead of one half of it when the decimal output string's value is less than d. + b2 += Log2P; + s2 += Log2P; + spec_case = true; + } + } + + // Arrange for convenient computation of quotients: + // shift left if necessary so divisor has 4 leading 0 bits. + // + // Perhaps we should just compute leading 28 bits of S once + // and for all and pass them and a shift to quoRem, so it + // can do shifts and ors to compute the numerator for q. + if ((i = ((s5 ? 32 - hi0bits(S.word(S.nWords()-1)) : 1) + s2) & 0x1f) != 0) + i = 32 - i; + // i is the number of leading zero bits in the most significant word of S*2^s2. + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + // Now S*2^s2 has exactly four leading zero bits in its most significant word. + if (b2 > 0) + b.pow2Mul(b2); + if (s2 > 0) + S.pow2Mul(s2); + // Now we have d/10^k = b/S and + // (mHigh * 2^m2) / S = maximum acceptable error, divided by 10^k. + if (k_check) { + if (b.cmp(S) < 0) { + k--; + b.mulAdd(10, 0); // we botched the k estimate + if (leftright) + mHigh.mulAdd(10, 0); + ilim = ilim1; + } + } + // At this point 1 <= d/10^k = b/S < 10. + + if (ilim <= 0 && mode > 2) { + // We're doing fixed-mode output and d is less than the minimum nonzero output in this mode. + // Output either zero or the minimum nonzero output depending on which is closer to d. + // Always emit at least one digit. If the number appears to be zero + // using the current mode, then emit one '0' digit and set decpt to 1. + if (ilim < 0) + goto no_digits; + S.mulAdd(5, 0); + if ((i = b.cmp(S)) < 0 || (i == 0 && !biasUp)) + goto no_digits; + goto one_digit; + } + if (leftright) { + if (m2 > 0) + mHigh.pow2Mul(m2); + + // Compute mLow -- check for special case that d is a normalized power of 2. + if (spec_case) { + mLow = mHigh; + mHigh.pow2Mul(Log2P); + } + // mLow/S = maximum acceptable error, divided by 10^k, if the output is less than d. + // mHigh/S = maximum acceptable error, divided by 10^k, if the output is greater than d. + + for (i = 1;;i++) { + dig = b.quoRem(S) + '0'; + // Do we yet have the shortest decimal string that will round to d? + j = b.cmp(spec_case ? mLow : mHigh); + // j is b/S compared with mLow/S. + { + BigInt delta; + delta.initDiff(S, mHigh); + j1 = delta.negative ? 1 : b.cmp(delta); + } + // j1 is b/S compared with 1 - mHigh/S. +#ifndef ROUND_BIASED + if (j1 == 0 && !mode && !(word1(d) & 1)) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; + *s++ = (char)dig; + goto ret; + } +#endif + if ((j < 0) || (j == 0 && !mode +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (j1 > 0) { + // Either dig or dig+1 would work here as the least significant decimal digit. + // Use whichever would produce a decimal value closer to d. + b.pow2Mul(1); + j1 = b.cmp(S); + if (((j1 > 0) || (j1 == 0 && (dig & 1 || biasUp))) + && (dig++ == '9')) + goto round_9_up; + } + *s++ = (char)dig; + goto ret; + } + if (j1 > 0) { + if (dig == '9') { // possible if i == 1 + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = char(dig + 1); + goto ret; + } + *s++ = (char)dig; + if (i == ilim) + break; + b.mulAdd(10, 0); + if (spec_case) + mLow.mulAdd(10, 0); + mHigh.mulAdd(10, 0); + } + } + else + for (i = 1;; i++) { + *s++ = (char)(dig = b.quoRem(S) + '0'); + if (i >= ilim) + break; + b.mulAdd(10, 0); + } + + // Round off last digit + + b.pow2Mul(1); + j = b.cmp(S); + if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) { + roundoff: + while (*--s == '9') + if (s == buf) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + // Strip trailing zeros + while (*--s == '0') ; + s++; + } + ret: ; + // S, mLow, and mHigh are destroyed at the end of this block scope. } - goto ret1; + ret1: + *s = '\0'; + *decpt = k + 1; + return s; } - { - m2 = b2; - m5 = b5; - BigInt mLow; // If spec_case is false, assume that mLow == mHigh - BigInt mHigh; - - if (leftright) { - if (mode < 2) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif - 1 + P - bbits; - // i is 1 plus the number of trailing zero bits in d's significand. Thus, - // (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. - } - else { - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - // (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. - } - b2 += i; - s2 += i; - mHigh.init(1); - // (mHigh * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or - // input (when mode < 2) significant digit, divided by 10^k. - } - // We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in - // b2, m2, and s2 without changing the equalities. - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - - // Fold b5 into b and m5 into mHigh. - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mHigh.pow5Mul(m5); - b *= mHigh; - } - if ((j = b5 - m5) != 0) - b.pow5Mul(j); - } - else - b.pow5Mul(b5); - } - // Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and - // (mHigh * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. - - BigInt S; - S.init(1); - if (s5 > 0) - S.pow5Mul(s5); - // Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and - // (mHigh * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. - - // Check for special case that d is a normalized power of 2. - bool spec_case = false; - if (mode < 2) { - if (!word1(d) && !(word0(d) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(d) & (Exp_mask & Exp_mask << 1) -#endif - ) { - // The special case. Here we want to be within a quarter of the last input - // significant digit instead of one half of it when the decimal output string's value is less than d. - b2 += Log2P; - s2 += Log2P; - spec_case = true; - } - } - - // Arrange for convenient computation of quotients: - // shift left if necessary so divisor has 4 leading 0 bits. - // - // Perhaps we should just compute leading 28 bits of S once - // and for all and pass them and a shift to quoRem, so it - // can do shifts and ors to compute the numerator for q. - if ((i = ((s5 ? 32 - hi0bits(S.word(S.nWords()-1)) : 1) + s2) & 0x1f) != 0) - i = 32 - i; - // i is the number of leading zero bits in the most significant word of S*2^s2. - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } - else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - // Now S*2^s2 has exactly four leading zero bits in its most significant word. - if (b2 > 0) - b.pow2Mul(b2); - if (s2 > 0) - S.pow2Mul(s2); - // Now we have d/10^k = b/S and - // (mHigh * 2^m2) / S = maximum acceptable error, divided by 10^k. - if (k_check) { - if (b.cmp(S) < 0) { - k--; - b.mulAdd(10, 0); // we botched the k estimate - if (leftright) - mHigh.mulAdd(10, 0); - ilim = ilim1; - } - } - // At this point 1 <= d/10^k = b/S < 10. - - if (ilim <= 0 && mode > 2) { - // We're doing fixed-mode output and d is less than the minimum nonzero output in this mode. - // Output either zero or the minimum nonzero output depending on which is closer to d. - // Always emit at least one digit. If the number appears to be zero - // using the current mode, then emit one '0' digit and set decpt to 1. - if (ilim < 0) - goto no_digits; - S.mulAdd(5, 0); - if ((i = b.cmp(S)) < 0 || (i == 0 && !biasUp)) - goto no_digits; - goto one_digit; - } - if (leftright) { - if (m2 > 0) - mHigh.pow2Mul(m2); - - // Compute mLow -- check for special case that d is a normalized power of 2. - if (spec_case) { - mLow = mHigh; - mHigh.pow2Mul(Log2P); - } - // mLow/S = maximum acceptable error, divided by 10^k, if the output is less than d. - // mHigh/S = maximum acceptable error, divided by 10^k, if the output is greater than d. - - for (i = 1;;i++) { - dig = b.quoRem(S) + '0'; - // Do we yet have the shortest decimal string that will round to d? - j = b.cmp(spec_case ? mLow : mHigh); - // j is b/S compared with mLow/S. - { - BigInt delta; - delta.initDiff(S, mHigh); - j1 = delta.negative ? 1 : b.cmp(delta); - } - // j1 is b/S compared with 1 - mHigh/S. -#ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(word1(d) & 1)) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; - *s++ = (char)dig; - goto ret; - } -#endif - if ((j < 0) || (j == 0 && !mode -#ifndef ROUND_BIASED - && !(word1(d) & 1) -#endif - )) { - if (j1 > 0) { - // Either dig or dig+1 would work here as the least significant decimal digit. - // Use whichever would produce a decimal value closer to d. - b.pow2Mul(1); - j1 = b.cmp(S); - if (((j1 > 0) || (j1 == 0 && (dig & 1 || biasUp))) - && (dig++ == '9')) - goto round_9_up; - } - *s++ = (char)dig; - goto ret; - } - if (j1 > 0) { - if (dig == '9') { // possible if i == 1 - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = char(dig + 1); - goto ret; - } - *s++ = (char)dig; - if (i == ilim) - break; - b.mulAdd(10, 0); - if (spec_case) - mLow.mulAdd(10, 0); - mHigh.mulAdd(10, 0); - } - } - else - for (i = 1;; i++) { - *s++ = (char)(dig = b.quoRem(S) + '0'); - if (i >= ilim) - break; - b.mulAdd(10, 0); - } - - // Round off last digit - - b.pow2Mul(1); - j = b.cmp(S); - if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) { - roundoff: - while (*--s == '9') - if (s == buf) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { - // Strip trailing zeros - while (*--s == '0') ; - s++; - } - ret: ; - // S, mLow, and mHigh are destroyed at the end of this block scope. - } - ret1: - *s = '\0'; - *decpt = k + 1; - return s; -} - // Mapping of DToStrMode -> doubleToAscii mode -static const int doubleToAsciiModes[] = { - 0, // dtosStandard - 0, // dtosStandardExponential - 3, // dtosFixed - 2, // dtosExponential - 2}; // dtosPrecision + static const int doubleToAsciiModes[] = { + 0, // dtosStandard + 0, // dtosStandardExponential + 3, // dtosFixed + 2, // dtosExponential + 2}; // dtosPrecision // Convert value according to the given mode and return a pointer to the resulting ASCII string. // The result is held somewhere in buffer, but not necessarily at the beginning. The size of // buffer is given in bufferSize, and must be at least as large as given by dtosStandardBufferSize // or dtosVariableBufferSize, whichever is appropriate. -char *JS::doubleToStr(char *buffer, size_t DEBUG_ONLY(bufferSize), double value, DToStrMode mode, int precision) -{ - int decPt; // Position of decimal point relative to first digit returned by doubleToAscii - bool negative; // True if the sign bit was set in value - int nDigits; // Number of significand digits returned by doubleToAscii - char *numBegin = buffer+2; // Pointer to the digits returned by doubleToAscii; the +2 leaves space for + char *doubleToStr(char *buffer, size_t DEBUG_ONLY(bufferSize), double value, DToStrMode mode, int precision) + { + int decPt; // Position of decimal point relative to first digit returned by doubleToAscii + bool negative; // True if the sign bit was set in value + int nDigits; // Number of significand digits returned by doubleToAscii + char *numBegin = buffer+2; // Pointer to the digits returned by doubleToAscii; the +2 leaves space for // the sign and/or decimal point - char *numEnd; // Pointer past the digits returned by doubleToAscii + char *numEnd; // Pointer past the digits returned by doubleToAscii - ASSERT(bufferSize >= (size_t)(mode <= dtosStandardExponential ? dtosStandardBufferSize : dtosVariableBufferSize(precision))); + ASSERT(bufferSize >= (size_t)(mode <= dtosStandardExponential ? dtosStandardBufferSize : dtosVariableBufferSize(precision))); - if (mode == dtosFixed && (value >= 1e21 || value <= -1e21)) - mode = dtosStandard; // Change mode here rather than below because the buffer may not be large enough to hold a large integer. + if (mode == dtosFixed && (value >= 1e21 || value <= -1e21)) + mode = dtosStandard; // Change mode here rather than below because the buffer may not be large enough to hold a large integer. - numEnd = doubleToAscii(value, doubleToAsciiModes[mode], mode >= dtosFixed, precision, &decPt, &negative, numBegin); - nDigits = numEnd - numBegin; + numEnd = doubleToAscii(value, doubleToAsciiModes[mode], mode >= dtosFixed, precision, &decPt, &negative, numBegin); + nDigits = numEnd - numBegin; - // If Infinity, -Infinity, or NaN, return the string regardless of the mode. - if (decPt != 9999) { - bool exponentialNotation = false; - int minNDigits = 0; // Minimum number of significand digits required by mode and precision - char *p; - char *q; + // If Infinity, -Infinity, or NaN, return the string regardless of the mode. + if (decPt != 9999) { + bool exponentialNotation = false; + int minNDigits = 0; // Minimum number of significand digits required by mode and precision + char *p; + char *q; - switch (mode) { - case dtosStandard: - if (decPt < -5 || decPt > 21) - exponentialNotation = true; - else - minNDigits = decPt; - break; + switch (mode) { + case dtosStandard: + if (decPt < -5 || decPt > 21) + exponentialNotation = true; + else + minNDigits = decPt; + break; - case dtosFixed: - if (precision >= 0) - minNDigits = decPt + precision; - else - minNDigits = decPt; - break; + case dtosFixed: + if (precision >= 0) + minNDigits = decPt + precision; + else + minNDigits = decPt; + break; - case dtosExponential: - ASSERT(precision > 0); - minNDigits = precision; - // Fall through - case dtosStandardExponential: - exponentialNotation = true; - break; + case dtosExponential: + ASSERT(precision > 0); + minNDigits = precision; + // Fall through + case dtosStandardExponential: + exponentialNotation = true; + break; - case dtosPrecision: - ASSERT(precision > 0); - minNDigits = precision; - if (decPt < -5 || decPt > precision) - exponentialNotation = true; - break; - } - - // If the number has fewer than minNDigits, pad it with zeros at the end - if (nDigits < minNDigits) { - p = numBegin + minNDigits; - nDigits = minNDigits; - do { - *numEnd++ = '0'; - } while (numEnd != p); - *numEnd = '\0'; - } - - if (exponentialNotation) { - // Insert a decimal point if more than one significand digit - if (nDigits != 1) { - numBegin--; - numBegin[0] = numBegin[1]; - numBegin[1] = '.'; + case dtosPrecision: + ASSERT(precision > 0); + minNDigits = precision; + if (decPt < -5 || decPt > precision) + exponentialNotation = true; + break; } - sprintf(numEnd, "e%+d", decPt-1); - } else if (decPt != nDigits) { - // Some kind of a fraction in fixed notation - ASSERT(decPt <= nDigits); - if (decPt > 0) { - // dd...dd . dd...dd - p = --numBegin; + + // If the number has fewer than minNDigits, pad it with zeros at the end + if (nDigits < minNDigits) { + p = numBegin + minNDigits; + nDigits = minNDigits; do { - *p = p[1]; - p++; - } while (--decPt); - *p = '.'; - } else { - // 0 . 00...00dd...dd - p = numEnd; - numEnd += 1 - decPt; - q = numEnd; - ASSERT(numEnd < buffer + bufferSize); + *numEnd++ = '0'; + } while (numEnd != p); *numEnd = '\0'; - while (p != numBegin) - *--q = *--p; - for (p = numBegin + 1; p != q; p++) - *p = '0'; - *numBegin = '.'; - *--numBegin = '0'; + } + + if (exponentialNotation) { + // Insert a decimal point if more than one significand digit + if (nDigits != 1) { + numBegin--; + numBegin[0] = numBegin[1]; + numBegin[1] = '.'; + } + sprintf(numEnd, "e%+d", decPt-1); + } else if (decPt != nDigits) { + // Some kind of a fraction in fixed notation + ASSERT(decPt <= nDigits); + if (decPt > 0) { + // dd...dd . dd...dd + p = --numBegin; + do { + *p = p[1]; + p++; + } while (--decPt); + *p = '.'; + } else { + // 0 . 00...00dd...dd + p = numEnd; + numEnd += 1 - decPt; + q = numEnd; + ASSERT(numEnd < buffer + bufferSize); + *numEnd = '\0'; + while (p != numBegin) + *--q = *--p; + for (p = numBegin + 1; p != q; p++) + *p = '0'; + *numBegin = '.'; + *--numBegin = '0'; + } } } - } - // If negative and neither -0.0 nor NaN, output a leading '-'. - if (negative && + // If negative and neither -0.0 nor NaN, output a leading '-'. + if (negative && !(word0(value) == Sign_bit && word1(value) == 0) && !((word0(value) & Exp_mask) == Exp_mask && (word1(value) || (word0(value) & Frac_mask)))) { - *--numBegin = '-'; + *--numBegin = '-'; + } + return numBegin; } - return numBegin; -} -inline char baseDigit(uint32 digit) -{ - if (digit >= 10) - return char('a' - 10 + digit); - else - return char('0' + digit); -} + inline char baseDigit(uint32 digit) + { + if (digit >= 10) + return char('a' - 10 + digit); + else + return char('0' + digit); + } // Convert value to a string in the given base. The integral part of value will be printed exactly @@ -2588,182 +2623,184 @@ inline char baseDigit(uint32 digit) // // Store the result in the given buffer, which must have at least dtobasesBufferSize bytes. // Return the number of characters stored. -size_t JS::doubleToBaseStr(char *buffer, double value, uint base) -{ - ASSERT(base >= 2 && base <= 36); + size_t doubleToBaseStr(char *buffer, double value, uint base) + { + ASSERT(base >= 2 && base <= 36); - char *p = buffer; // Pointer to current position in the buffer - if (value < 0.0 + char *p = buffer; // Pointer to current position in the buffer + if (value < 0.0 #ifdef _WIN32 - && !((word0(value) & Exp_mask) == Exp_mask && ((word0(value) & Frac_mask) || word1(value))) // Visual C++ doesn't know how to compare against NaN -#endif - ) { - *p++ = '-'; - value = -value; - } - - // Check for Infinity and NaN - if ((word0(value) & Exp_mask) == Exp_mask) { - strcpy(p, !word1(value) && !(word0(value) & Frac_mask) ? "Infinity" : "NaN"); - return strlen(buffer); - } - - // Output the integer part of value with the digits in reverse order. - char *pInt = p; // Pointer to the beginning of the integer part of the string - double valueInt = floor(value); // value truncated to an integer - uint32 digit; - if (valueInt <= 4294967295.0) { - uint32 n = (uint32)valueInt; - if (n) - do { - uint32 m = n / base; - digit = n - m*base; - n = m; - ASSERT(digit < base); - *p++ = baseDigit(digit); - } while (n); - else *p++ = '0'; - } else { - int32 e; - int32 bits; // Number of significant bits in valueInt; not used. - BigInt b; - b.init(valueInt, e, bits); - b.pow2Mul(e); - do { - digit = b.divRem(base); - ASSERT(digit < base); - *p++ = baseDigit(digit); - } while (!b.isZero()); - } - // Reverse the digits of the integer part of value. - char *q = p-1; - while (q > pInt) { - char ch = *pInt; - *pInt++ = *q; - *q-- = ch; - } - - double valueFrac = value - valueInt; // The fractional part of value - if (valueFrac != 0.0) { - // We have a fraction. - *p++ = '.'; - - int32 e, bbits; - BigInt b; - b.init(valueFrac, e, bbits); - ASSERT(e < 0); - // At this point valueFrac = b * 2^e. e must be less than zero because 0 < valueFrac < 1. - - int32 s2 = -int32(word0(value) >> Exp_shift1 & Exp_mask>>Exp_shift1); -#ifndef Sudden_Underflow - if (!s2) - s2 = -1; -#endif - s2 += Bias + P; - // 1/2^s2 = (nextDouble(value) - value)/2 - ASSERT(-s2 < e); - - BigInt mLow; - BigInt mHigh; - bool useMHigh = false; // If false, assume that mHigh == mLow - - mLow.init(1); - if (!word1(value) && !(word0(value) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(value) & (Exp_mask & Exp_mask << 1) + && !((word0(value) & Exp_mask) == Exp_mask && ((word0(value) & Frac_mask) || word1(value))) // Visual C++ doesn't know how to compare against NaN #endif ) { - // The special case. Here we want to be within a quarter of the last input - // significant digit instead of one half of it when the output string's value is less than value. - s2 += Log2P; - useMHigh = true; - mHigh.init(1u< valueFrac = b/2^s2 > 0; - // (value - prevDouble(value))/2 = mLow/2^s2; - // (nextDouble(value) - value)/2 = mHigh/2^s2. + // Output the integer part of value with the digits in reverse order. + char *pInt = p; // Pointer to the beginning of the integer part of the string + double valueInt = floor(value); // value truncated to an integer + uint32 digit; + if (valueInt <= 4294967295.0) { + uint32 n = (uint32)valueInt; + if (n) + do { + uint32 m = n / base; + digit = n - m*base; + n = m; + ASSERT(digit < base); + *p++ = baseDigit(digit); + } while (n); + else *p++ = '0'; + } else { + int32 e; + int32 bits; // Number of significant bits in valueInt; not used. + BigInt b; + b.init(valueInt, e, bits); + b.pow2Mul(e); + do { + digit = b.divRem(base); + ASSERT(digit < base); + *p++ = baseDigit(digit); + } while (!b.isZero()); + } + // Reverse the digits of the integer part of value. + char *q = p-1; + while (q > pInt) { + char ch = *pInt; + *pInt++ = *q; + *q-- = ch; + } + + double valueFrac = value - valueInt; // The fractional part of value + if (valueFrac != 0.0) { + // We have a fraction. + *p++ = '.'; - bool done = false; - do { - int32 j, j1; + int32 e, bbits; + BigInt b; + b.init(valueFrac, e, bbits); + ASSERT(e < 0); + // At this point valueFrac = b * 2^e. e must be less than zero because 0 < valueFrac < 1. + + int32 s2 = -int32(word0(value) >> Exp_shift1 & Exp_mask>>Exp_shift1); +#ifndef Sudden_Underflow + if (!s2) + s2 = -1; +#endif + s2 += Bias + P; + // 1/2^s2 = (nextDouble(value) - value)/2 + ASSERT(-s2 < e); - b.mulAdd(base, 0); - digit = b.quoRem2(s2); - mLow.mulAdd(base, 0); - if (useMHigh) - mHigh.mulAdd(base, 0); + BigInt mLow; + BigInt mHigh; + bool useMHigh = false; // If false, assume that mHigh == mLow - // Do we yet have the shortest string that will round to value? - j = b.cmp(mLow); - // j is b/2^s2 compared with mLow/2^s2. - { - BigInt delta; - delta.initDiff(s, useMHigh ? mHigh : mLow); - j1 = delta.negative ? 1 : b.cmp(delta); + mLow.init(1); + if (!word1(value) && !(word0(value) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(value) & (Exp_mask & Exp_mask << 1) +#endif + ) { + // The special case. Here we want to be within a quarter of the last input + // significant digit instead of one half of it when the output string's value is less than value. + s2 += Log2P; + useMHigh = true; + mHigh.init(1u< 0) - digit++; - done = true; - } else -#endif - if (j < 0 || (j == 0 -#ifndef ROUND_BIASED - && !(word1(value) & 1) -#endif - )) { - if (j1 > 0) { - // Either dig or dig+1 would work here as the least significant digit. - // Use whichever would produce an output value closer to value. - b.pow2Mul(1); - j1 = b.cmp(s); - if (j1 > 0) // The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output - // such as 3.5 in base 3. - digit++; + BigInt s; + s.init(1); + s.pow2Mul(s2); + + // At this point we have the following: + // s = 2^s2; + // 1 > valueFrac = b/2^s2 > 0; + // (value - prevDouble(value))/2 = mLow/2^s2; + // (nextDouble(value) - value)/2 = mHigh/2^s2. + + bool done = false; + do { + int32 j, j1; + + b.mulAdd(base, 0); + digit = b.quoRem2(s2); + mLow.mulAdd(base, 0); + if (useMHigh) + mHigh.mulAdd(base, 0); + + // Do we yet have the shortest string that will round to value? + j = b.cmp(mLow); + // j is b/2^s2 compared with mLow/2^s2. + { + BigInt delta; + delta.initDiff(s, useMHigh ? mHigh : mLow); + j1 = delta.negative ? 1 : b.cmp(delta); } - done = true; - } else if (j1 > 0) { - digit++; - done = true; - } - ASSERT(digit < base); - *p++ = baseDigit(digit); - } while (!done); + // j1 is b/2^s2 compared with 1 - mHigh/2^s2. + +#ifndef ROUND_BIASED + if (j1 == 0 && !(word1(value) & 1)) { + if (j > 0) + digit++; + done = true; + } else +#endif + if (j < 0 || (j == 0 +#ifndef ROUND_BIASED + && !(word1(value) & 1) +#endif + )) { + if (j1 > 0) { + // Either dig or dig+1 would work here as the least significant digit. + // Use whichever would produce an output value closer to value. + b.pow2Mul(1); + j1 = b.cmp(s); + if (j1 > 0) // The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output + // such as 3.5 in base 3. + digit++; + } + done = true; + } else if (j1 > 0) { + digit++; + done = true; + } + ASSERT(digit < base); + *p++ = baseDigit(digit); + } while (!done); + } + ASSERT(p < buffer + dtobasesBufferSize); + *p = '\0'; + return size_t(p - buffer); } - ASSERT(p < buffer + dtobasesBufferSize); - *p = '\0'; - return size_t(p - buffer); -} // A version of doubleToStr that appends to the end of String dst. // precision should not exceed 101. -void JS::appendDouble(String &dst, double value, DToStrMode mode, int precision) -{ - char buffer[dtosVariableBufferSize(101)]; - ASSERT(uint(precision) <= 101); - - dst += doubleToStr(buffer, sizeof buffer, value, mode, precision); -} + void appendDouble(String &dst, double value, DToStrMode mode, int precision) + { + char buffer[dtosVariableBufferSize(101)]; + ASSERT(uint(precision) <= 101); + + dst += doubleToStr(buffer, sizeof buffer, value, mode, precision); + } // A version of doubleToStr that prints to Formatter f. // precision should not exceed 101. -void JS::printDouble(Formatter &f, double value, DToStrMode mode, int precision) -{ - char buffer[dtosVariableBufferSize(101)]; - ASSERT(uint(precision) <= 101); - - f << doubleToStr(buffer, sizeof buffer, value, mode, precision); + void printDouble(Formatter &f, double value, DToStrMode mode, int precision) + { + char buffer[dtosVariableBufferSize(101)]; + ASSERT(uint(precision) <= 101); + + f << doubleToStr(buffer, sizeof buffer, value, mode, precision); + } + } diff --git a/mozilla/js2/src/numerics.h b/mozilla/js2/src/numerics.h index b86f80994cb..2b8e101437f 100644 --- a/mozilla/js2/src/numerics.h +++ b/mozilla/js2/src/numerics.h @@ -1,30 +1,51 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #ifndef numerics_h #define numerics_h -#include "utilities.h" #include -// Use platform-defined floating-point routines. On platforms with faulty floating-point code -// ifdef these out and replace by custom implementations. -#ifndef _WIN32 // Microsoft VC6 bug: standard identifiers should be in std namespace + +#include "systemtypes.h" +#include "utilities.h" +#include "strings.h" +#include "formatter.h" + +// Use platform-defined floating-point routines. On platforms with faulty +// floating-point code ifdef these out and replace by custom implementations. + +#ifndef _WIN32 +// Microsoft VC6 bug: standard identifiers should be in std namespace using std::abs; using std::floor; using std::ceil; @@ -44,105 +65,129 @@ namespace JavaScript { // Double-precision constants // - extern double positiveInfinity; - extern double negativeInfinity; - extern double nan; + extern double positiveInfinity; + extern double negativeInfinity; + extern double nan; // // Portable double-precision floating point to string and back conversions // - double ulp(double x); - int hi0bits(uint32 x); + double ulp(double x); + int hi0bits(uint32 x); - class BigInt { - enum {maxLgGrossSize = 15}; // Maximum value of lg2(grossSize) - static uint32 *freeLists[maxLgGrossSize+1]; - - uint lgGrossSize; // lg2(grossSize) - public: - bool negative; // True if negative. Ignored by most BigInt routines! - private: - uint32 grossSize; // Number of words allocated for - uint32 size; // Actual number of words. If the number is nonzero, the most significant word must be nonzero. - // If the number is zero, then size is also 0. - uint32 *words; // words of the number, in little endian order - - void allocate(uint lgGrossSize); - void recycle(); - void initCopy(const BigInt &b); - void move(BigInt &b); - public: - BigInt(): words(0) {} - explicit BigInt(uint lgGrossSize) {allocate(lgGrossSize);} - BigInt(const BigInt &b) {initCopy(b);} - void operator=(const BigInt &b) {ASSERT(!words); initCopy(b);} - ~BigInt() {if (words) recycle();} - - void setLgGrossSize(uint lgGrossSize); - void init(uint32 i); - void init(double d, int32 &e, int32 &bits); - void mulAdd(uint m, uint a); - void operator*=(const BigInt &m); - void pow2Mul(int32 k); - void pow5Mul(int32 k); - bool isZero() const {ASSERT(words); return !size;} - int cmp(const BigInt &b) const; - void initDiff(const BigInt &m, const BigInt &n); - uint32 quoRem2(int32 k); - int32 quoRem(const BigInt &S); - uint32 divRem(uint32 divisor); - double b2d(int32 &e) const; - double ratio(const BigInt &denominator) const; - void s2b(const char *s, int32 nd0, int32 nd, uint32 y9); - - uint32 nWords() const {return size;} - uint32 word(uint32 i) const {ASSERT(i < size); return words[i];} - }; + class BigInt { + enum {maxLgGrossSize = 15}; // Maximum value of lg2(grossSize) + static uint32 *freeLists[maxLgGrossSize+1]; + + uint lgGrossSize; // lg2(grossSize) + public: + bool negative; // True if negative. Ignored by most + // BigInt routines! + private: + uint32 grossSize; // Number of words allocated for + uint32 size; // Actual number of words. If the + // number is nonzero, the most + // significant word must be nonzero. + // If the number is zero, then size is + // also 0. + uint32 *words; // words of the number, in + // little endian order + void allocate(uint lgGrossSize); + void recycle(); + void initCopy(const BigInt &b); + void move(BigInt &b); + public: + BigInt(): words(0) {} + explicit BigInt(uint lgGrossSize) {allocate(lgGrossSize);} + BigInt(const BigInt &b) {initCopy(b);} + void operator=(const BigInt &b) {ASSERT(!words); initCopy(b);} + ~BigInt() {if (words) recycle();} + + void setLgGrossSize(uint lgGrossSize); + void init(uint32 i); + void init(double d, int32 &e, int32 &bits); + void mulAdd(uint m, uint a); + void operator*=(const BigInt &m); + void pow2Mul(int32 k); + void pow5Mul(int32 k); + bool isZero() const {ASSERT(words); return !size;} + int cmp(const BigInt &b) const; + void initDiff(const BigInt &m, const BigInt &n); + uint32 quoRem2(int32 k); + int32 quoRem(const BigInt &S); + uint32 divRem(uint32 divisor); + double b2d(int32 &e) const; + double ratio(const BigInt &denominator) const; + void s2b(const char *s, int32 nd0, int32 nd, uint32 y9); + + uint32 nWords() const {return size;} + uint32 word(uint32 i) const {ASSERT(i < size); return words[i];} + }; - // Modes for converting floating-point numbers to strings. - // - // Some of the modes can round-trip; this means that if the number is converted to - // a string using one of these mode and then converted back to a number, the result - // will be identical to the original number (except that, due to ECMA, -0 will get converted - // to +0). These round-trip modes return the minimum number of significand digits that - // permit the round trip. - // - // Some of the modes take an integer parameter . - // - // Keep this in sync with doubleToAsciiModes[]. - enum DToStrMode { - dtosStandard, // Either fixed or exponential format; round-trip - dtosStandardExponential, // Always exponential format; round-trip - dtosFixed, // Round to digits after the decimal point; exponential if number is large - dtosExponential, // Always exponential format; significant digits - dtosPrecision // Either fixed or exponential format; significant digits - }; + // Modes for converting floating-point numbers to strings. + // + // Some of the modes can round-trip; this means that if the number is + // converted to a string using one of these mode and then converted back + // to a number, the result will be identical to the original number (except + // that, due to ECMA, -0 will get converted to +0). These round-trip modes + // return the minimum number of significand digits that permit the round + // trip. + // + // Some of the modes take an integer parameter . + // + // Keep this in sync with doubleToAsciiModes[]. + enum DToStrMode { + dtosStandard, // Either fixed or exponential format; round-trip + dtosStandardExponential, // Always exponential format; round-trip + dtosFixed, // Round to digits after the + // decimal point; exponential if number is + // large + dtosExponential, // Always exponential format; + // significant digits + dtosPrecision // Either fixed or exponential format; + // significant digits + }; - // Maximum number of characters (including trailing null) that a dtosStandard or dtosStandardExponential - // conversion can produce. This maximum is reached for a number like -1.2345678901234567e+123. - const int dtosStandardBufferSize = 25; + // Maximum number of characters (including trailing null) that a + // dtosStandard or dtosStandardExponential conversion can produce. This + // maximum is reached for a number like -1.2345678901234567e+123. + const int dtosStandardBufferSize = 25; - // Maximum number of characters (including trailing null) that one of the other conversions - // can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point. - #define dtosVariableBufferSize(precision) ((precision)+24 > dtosStandardBufferSize ? (precision)+24 : dtosStandardBufferSize) + // Maximum number of characters (including trailing null) that one of the + // other conversions can produce. This maximum is reached for TO_FIXED, + // which can generate up to 21 digits before the decimal point. +#define dtosVariableBufferSize(precision) \ + ((precision)+24 > dtosStandardBufferSize ? \ + (precision)+24 : dtosStandardBufferSize) \ - // "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce, - // which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of - // the output string and malloc fewer bytes depending on d and base, but why bother? - const int dtobasesBufferSize = 1078; + // "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest + // string that we could produce, which occurs when printing -5e-324 in + // binary. We could compute a better estimate of the size of the output + // string and malloc fewer bytes depending on d and base, but why bother? + const int dtobasesBufferSize = 1078; - double strToDouble(const char *str, const char *&numEnd); - double stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd); - double stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base); + double strToDouble(const char *str, const char *&numEnd); + double stringToDouble(const char16 *str, const char16 *strEnd, + const char16 *&numEnd); + double stringToInteger(const char16 *str, const char16 *strEnd, + const char16 *&numEnd, uint base); - char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision); - size_t doubleToBaseStr(char *buffer, double value, uint base); - void appendDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0); - inline String &operator+=(String &s, double value) {appendDouble(s, value); return s;} - void printDouble(Formatter &f, double value, DToStrMode mode = dtosStandard, int precision = 0); - inline Formatter &operator<<(Formatter &f, double value) {printDouble(f, value); return f;} + char *doubleToStr(char *buffer, size_t bufferSize, double value, + DToStrMode mode, int precision); + size_t doubleToBaseStr(char *buffer, double value, uint base); + void appendDouble(String &dst, double value, + DToStrMode mode = dtosStandard, int precision = 0); + inline String &operator+=(String &s, double value) { + appendDouble(s, value); return s; + } + void printDouble(Formatter &f, double value, + DToStrMode mode = dtosStandard, int precision = 0); + inline Formatter &operator<<(Formatter &f, double value) { + printDouble(f, value); return f; + } } + #endif diff --git a/mozilla/js2/src/parser.cpp b/mozilla/js2/src/parser.cpp index fa54f8b3322..8147863dff3 100644 --- a/mozilla/js2/src/parser.cpp +++ b/mozilla/js2/src/parser.cpp @@ -1,3638 +1,1918 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #include "numerics.h" #include "parser.h" -#include "world.h" #include "nodefactory.h" -namespace JS = JavaScript; - - -// -// Reader -// - - -// Create a Reader reading characters from the source string. -// sourceLocation describes the origin of the source and may be used for error messages. -// initialLineNum is the line number of the first line of the source string. -JS::Reader::Reader(const String &source, const String &sourceLocation, uint32 initialLineNum): - source(source + uni::null), sourceLocation(sourceLocation), initialLineNum(initialLineNum) -{ - begin = p = this->source.data(); - end = begin + this->source.size() - 1; - #ifdef DEBUG - recordString = 0; - #endif - beginLine(); -} - - -// Mark the beginning of a line. Call this after reading every line break to fill -// out the line start table. -void JS::Reader::beginLine() -{ - ASSERT(p <= end && (!linePositions.size() || p > linePositions.back())); - linePositions.push_back(p); -} - - -// Return the number of the line containing the given character position. -// The line starts should have been recorded by calling beginLine. -uint32 JS::Reader::posToLineNum(uint32 pos) const -{ - ASSERT(pos <= getPos()); - std::vector::const_iterator i = std::upper_bound(linePositions.begin(), linePositions.end(), begin + pos); - ASSERT(i != linePositions.begin()); - return static_cast(i-1 - linePositions.begin()) + initialLineNum; -} - - -// Return the character position as well as pointers to the beginning and end (not including -// the line terminator) of the nth line. If lineNum is out of range, return 0 and two nulls. -// The line starts should have been recorded by calling beginLine(). If the nth line is the -// last one recorded, then getLine manually finds the line ending by searching for a line -// break; otherwise, getLine assumes that the line ends one character before the beginning -// of the next line. -uint32 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const -{ - lineBegin = 0; - lineEnd = 0; - if (lineNum < initialLineNum) - return 0; - lineNum -= initialLineNum; - if (lineNum >= linePositions.size()) - return 0; - lineBegin = linePositions[lineNum]; - - const char16 *e; - ++lineNum; - if (lineNum < linePositions.size()) - e = linePositions[lineNum] - 1; - else { - e = lineBegin; - const char16 *end = Reader::end; - while (e != end && !isLineBreak(*e)) - ++e; - } - lineEnd = e; - return static_cast(lineBegin - begin); -} - - -// Begin accumulating characters into the recordString, whose initial value is -// ignored and cleared. Each character passed to recordChar() is added to the end -// of the recordString. Recording ends when endRecord() or beginLine() is called. -// Recording is significantly optimized when the characters passed to readChar() -// are the same characters as read by get(). In this case the record String does -// not get allocated until endRecord() is called or a discrepancy appears between -// get() and recordChar(). -void JS::Reader::beginRecording(String &recordString) -{ - Reader::recordString = &recordString; - recordBase = p; - recordPos = p; -} - - -// Append ch to the recordString. -void JS::Reader::recordChar(char16 ch) -{ - ASSERT(recordString); - if (recordPos) { - if (recordPos != end && *recordPos == ch) { - recordPos++; - return; - } else { - recordString->assign(recordBase, recordPos); - recordPos = 0; - } - } - *recordString += ch; -} - - -// Finish recording characters into the recordString that was last passed to beginRecording(). -// Return that recordString. -JS::String &JS::Reader::endRecording() -{ - String *rs = recordString; - ASSERT(rs); - if (recordPos) - rs->assign(recordBase, recordPos); - recordString = 0; - return *rs; -} - - -// Report an error at the given character position in the source code. -void JS::Reader::error(Exception::Kind kind, const String &message, uint32 pos) -{ - uint32 lineNum = posToLineNum(pos); - const char16 *lineBegin; - const char16 *lineEnd; - uint32 linePos = getLine(lineNum, lineBegin, lineEnd); - ASSERT(lineBegin && lineEnd && linePos <= pos); - - throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, pos, lineBegin, lineEnd); -} - - -// -// Lexer -// - - -static const char controlCharNames[6] = {'b', 't', 'n', 'v', 'f', 'r'}; - -// Print the characters from begin to end, escaping them as necessary to make the resulting -// string be readable if placed between two quotes specified by quote (which should be either -// '\'' or '"'). -void JS::escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote) -{ - ASSERT(begin <= end); - - const char16 *chunk = begin; - while (begin != end) { - char16 ch = *begin++; - CharInfo ci(ch); - if (char16Value(ch) < 0x20 || isLineBreak(ci) || isFormat(ci) || ch == '\\' || ch == quote) { - if (begin-1 != chunk) - printString(f, chunk, begin-1); - chunk = begin; - - f << '\\'; - switch (ch) { - case 0x0008: - case 0x0009: - case 0x000A: - case 0x000B: - case 0x000C: - case 0x000D: - f << controlCharNames[ch - 0x0008]; - break; - - case '\'': - case '"': - case '\\': - f << ch; - break; - - case 0x0000: - if (begin == end || char16Value(*begin) < '0' || char16Value(*begin) > '9') { - f << '0'; - break; - } - default: - if (char16Value(ch) <= 0xFF) { - f << 'x'; - printHex(f, static_cast(char16Value(ch)), 2); - } else { - f << 'u'; - printHex(f, static_cast(char16Value(ch)), 4); - } - } - } - } - if (begin != chunk) - printString(f, chunk, begin); -} - - -// Print s as a quoted string using the given quotes (which should be either '\'' or '"'). -void JS::quoteString(Formatter &f, const String &s, char16 quote) -{ - f << quote; - const char16 *begin = s.data(); - escapeString(f, begin, begin + s.size(), quote); - f << quote; -} - - -const char *const JS::Token::kindNames[kindsEnd] = { - // Special - "end of input", // end - "number", // number - "string", // string - "unit", // unit - "regular expression",// regExp - - // Punctuators - "(", // openParenthesis - ")", // closeParenthesis - "[", // openBracket - "]", // closeBracket - "{", // openBrace - "}", // closeBrace - ",", // comma - ";", // semicolon - ".", // dot - "..", // doubleDot - "...", // tripleDot - "->", // arrow - ":", // colon - "::", // doubleColon - "#", // pound - "@", // at - "++", // increment - "--", // decrement - "~", // complement - "!", // logicalNot - "*", // times - "/", // divide - "%", // modulo - "+", // plus - "-", // minus - "<<", // leftShift - ">>", // rightShift - ">>>", // logicalRightShift - "&&", // logicalAnd - "^^", // logicalXor - "||", // logicalOr - "&", // bitwiseAnd - "^", // bitwiseXor - "|", // bitwiseOr - "=", // assignment - "*=", // timesEquals - "/=", // divideEquals - "%=", // moduloEquals - "+=", // plusEquals - "-=", // minusEquals - "<<=", // leftShiftEquals - ">>=", // rightShiftEquals - ">>>=", // logicalRightShiftEquals - "&&=", // logicalAndEquals - "^^=", // logicalXorEquals - "||=", // logicalOrEquals - "&=", // bitwiseAndEquals - "^=", // bitwiseXorEquals - "|=", // bitwiseOrEquals - "==", // equal - "!=", // notEqual - "<", // lessThan - "<=", // lessThanOrEqual - ">", // greaterThan - ">=", // greaterThanOrEqual - "===", // identical - "!==", // notIdentical - "?", // question - - // Reserved words - "abstract", // Abstract - "break", // Break - "case", // Case - "catch", // Catch - "class", // Class - "const", // Const - "continue", // Continue - "debugger", // Debugger - "default", // Default - "delete", // Delete - "do", // Do - "else", // Else - "enum", // Enum - "eval", // Eval - "export", // Export - "extends", // Extends - "false", // False - "final", // Final - "finally", // Finally - "for", // For - "function", // Function - "goto", // Goto - "if", // If - "implements", // Implements - "import", // Import - "in", // In - "instanceof", // Instanceof - "interface", // Interface - "native", // Native - "new", // New - "null", // Null - "package", // Package - "private", // Private - "protected", // Protected - "public", // Public - "return", // Return - "static", // Static - "super", // Super - "switch", // Switch - "synchronized", // Synchronized - "this", // This - "throw", // Throw - "throws", // Throws - "transient", // Transient - "true", // True - "try", // Try - "typeof", // Typeof - "var", // Var - "volatile", // Volatile - "while", // While - "with", // With - - // Non-reserved words - "attribute", // Attribute - "constructor", // Constructor - "get", // Get - "language", // Language - "namespace", // Namespace - "set", // Set - "use", // Use - "operator", // Operator - - "identifier" // identifier -}; - - -const uchar followRet = 1<= tokens+tokenLookahead ? nextToken-tokenLookahead : nextToken+tokenBufferSize-tokenLookahead)->valid = false; - } - #endif - } - return *nextToken; -} - - -#ifdef DEBUG -// Change the setting of preferRegExp for an already peeked token. The token must not be one -// for which that setting mattered. -// -// THIS IS A DANGEROUS FUNCTION! -// Use it only if you can be prove that the already peeked token does not start with a slash. -void JS::Lexer::redesignate(bool preferRegExp) -{ - ASSERT(nTokensFwd); - ASSERT(savedPreferRegExp[nextToken - tokens] != preferRegExp); - ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals))); - savedPreferRegExp[nextToken - tokens] = preferRegExp; -} -#endif - - -// Unread the last token. This call may be called to unread at most tokenBufferSize tokens -// at a time (where a peek also counts as temporarily reading and unreading one token). -// When a token that has been unread is peeked or read again, the same value must be passed -// in preferRegExp as for the first time that token was read or peeked. -void JS::Lexer::unget() -{ - ASSERT(nTokensBack--); - nTokensFwd++; - if (nextToken == tokens) - nextToken = tokens + tokenBufferSize; - --nextToken; -} - - -// Report a syntax error at the backUp-th last character read by the Reader. -// In other words, if backUp is 0, the error is at the next character to be read by the Reader; -// if backUp is 1, the error is at the last character read by the Reader, and so forth. -void JS::Lexer::syntaxError(const char *message, uint backUp) -{ - reader.unget(backUp); - reader.error(Exception::syntaxError, widenCString(message), reader.getPos()); -} - - -// Get the next character from the reader, skipping any Unicode format-control (Cf) characters. -inline char16 JS::Lexer::getChar() -{ - char16 ch = reader.get(); - if (char16Value(ch) >= firstFormatChar) - ch = internalGetChar(ch); - return ch; -} - -// Helper for getChar() -char16 JS::Lexer::internalGetChar(char16 ch) -{ - while (isFormat(ch)) - ch = reader.get(); - return ch; -} - - -// Peek the next character from the reader, skipping any Unicode format-control (Cf) characters, -// which are read and discarded. -inline char16 JS::Lexer::peekChar() -{ - char16 ch = reader.peek(); - if (char16Value(ch) >= firstFormatChar) - ch = internalPeekChar(ch); - return ch; -} - -// Helper for peekChar() -char16 JS::Lexer::internalPeekChar(char16 ch) -{ - while (isFormat(ch)) { - reader.get(); - ch = reader.peek(); - } - return ch; -} - - -// Peek the next character from the reader, skipping any Unicode format-control (Cf) characters, -// which are read and discarded. If the peeked character matches ch, read that character and return true; -// otherwise return false. ch must not be null. -bool JS::Lexer::testChar(char16 ch) -{ - ASSERT(ch); // If ch were null, it could match the eof null. - char16 ch2 = peekChar(); - if (ch == ch2) { - reader.get(); - return true; - } - return false; -} - - -// A backslash has been read. Read the rest of the escape code. -// Return the interpreted escaped character. Throw an exception if the escape is not valid. -// If unicodeOnly is true, allow only \uxxxx escapes. -char16 JS::Lexer::lexEscape(bool unicodeOnly) -{ - char16 ch = getChar(); - int nDigits; - - if (!unicodeOnly || ch == 'u') - switch (ch) { - case '0': - // Make sure that the next character isn't a digit. - ch = peekChar(); - if (!isASCIIDecimalDigit(ch)) - return 0x00; - getChar(); // Point to the next character in the error message - break; - - case 'b': - return 0x08; - case 'f': - return 0x0C; - case 'n': - return 0x0A; - case 'r': - return 0x0D; - case 't': - return 0x09; - case 'v': - return 0x0B; - - case 'x': - nDigits = 2; - goto lexHex; - case 'u': - nDigits = 4; - lexHex: - { - uint32 n = 0; - while (nDigits--) { - ch = getChar(); - uint digit; - if (!isASCIIHexDigit(ch, digit)) - goto error; - n = (n << 4) | digit; - } - return static_cast(n); - } - default: - if (!reader.getEof(ch)) { - CharInfo chi(ch); - if (!isAlphanumeric(chi) && !isLineBreak(chi)) - return ch; - } - } - error: - syntaxError("Bad escape code"); - return 0; -} - - -// Read an identifier into s. The initial value of s is ignored and cleared. -// Return true if an escape code has been encountered. -// If allowLeadingDigit is true, allow the first character of s to be a digit, just like any -// continuing identifier character. -bool JS::Lexer::lexIdentifier(String &s, bool allowLeadingDigit) -{ - reader.beginRecording(s); - bool hasEscape = false; - - while (true) { - char16 ch = getChar(); - char16 ch2 = ch; - if (ch == '\\') { - ch2 = lexEscape(true); - hasEscape = true; - } - CharInfo chi2(ch2); - - if (!(allowLeadingDigit ? isIdContinuing(chi2) : isIdLeading(chi2))) { - if (ch == '\\') - syntaxError("Identifier escape expands into non-identifier character"); - else - reader.unget(); - break; - } - reader.recordChar(ch2); - allowLeadingDigit = true; - } - reader.endRecording(); - return hasEscape; -} - - -// Read a numeric literal into nextToken->chars and nextToken->value. -// Return true if the numeric literal is followed by a unit, but don't read the unit yet. -bool JS::Lexer::lexNumeral() -{ - int hasDecimalPoint = 0; - String &s = nextToken->chars; - uint digit; - - reader.beginRecording(s); - char16 ch = getChar(); - if (ch == '0') { - reader.recordChar('0'); - ch = getChar(); - if ((ch&~0x20) == 'X') { - uint32 pos = reader.getPos(); - char16 ch2 = getChar(); - if (isASCIIHexDigit(ch2, digit)) { - reader.recordChar(ch); - do { - reader.recordChar(ch2); - ch2 = getChar(); - } while (isASCIIHexDigit(ch2, digit)); - ch = ch2; - } else - reader.setPos(pos); - goto done; - } else if (isASCIIDecimalDigit(ch)) { - syntaxError("Numeric constant syntax error"); - } - } - while (isASCIIDecimalDigit(ch) || ch == '.' && !hasDecimalPoint++) { - reader.recordChar(ch); - ch = getChar(); - } - if ((ch&~0x20) == 'E') { - uint32 pos = reader.getPos(); - char16 ch2 = getChar(); - char16 sign = 0; - if (ch2 == '+' || ch2 == '-') { - sign = ch2; - ch2 = getChar(); - } - if (isASCIIDecimalDigit(ch2)) { - reader.recordChar(ch); - if (sign) - reader.recordChar(sign); - do { - reader.recordChar(ch2); - ch2 = getChar(); - } while (isASCIIDecimalDigit(ch2)); - ch = ch2; - } else - reader.setPos(pos); - } - - done: - // At this point the reader is just past the character ch, which is the first non-formatting character - // that is not part of the number. - reader.endRecording(); - const char16 *sBegin = s.data(); - const char16 *sEnd = sBegin + s.size(); - const char16 *numEnd; - nextToken->value = stringToDouble(sBegin, sEnd, numEnd); - ASSERT(numEnd == sEnd); - reader.unget(); - ASSERT(ch == reader.peek()); - return isIdContinuing(ch) || ch == '\\'; -} - - -// Read a string literal into s. The initial value of s is ignored and cleared. -// The opening quote has already been read into separator. -void JS::Lexer::lexString(String &s, char16 separator) -{ - char16 ch; - - reader.beginRecording(s); - while ((ch = reader.get()) != separator) { - CharInfo chi(ch); - if (!isFormat(chi)) { - if (ch == '\\') - ch = lexEscape(false); - else if (reader.getEof(ch) || isLineBreak(chi)) - syntaxError("Unterminated string literal"); - reader.recordChar(ch); - } - } - reader.endRecording(); -} - - -// Read a regular expression literal. Store the regular expression in nextToken->id -// and the flags in nextToken->chars. -// The opening slash has already been read. -void JS::Lexer::lexRegExp() -{ - String s; - char16 prevCh = 0; - - reader.beginRecording(s); - while (true) { - char16 ch = getChar(); - CharInfo chi(ch); - if (reader.getEof(ch) || isLineBreak(chi)) - syntaxError("Unterminated regular expression literal"); - if (prevCh == '\\') { - reader.recordChar(ch); - prevCh = 0; // Ignore slashes and backslashes immediately after a backslash - } else if (ch != '/') { - reader.recordChar(ch); - prevCh = ch; - } else - break; - } - reader.endRecording(); - nextToken->id = &world.identifiers[s]; - - lexIdentifier(nextToken->chars, true); -} - - -// Read a token from the Reader and store it at *nextToken. -// If the Reader reached the end of file, store a Token whose Kind is end. -void JS::Lexer::lexToken(bool preferRegExp) -{ - Token &t = *nextToken; - t.lineBreak = false; - t.id = 0; - //clear(t.chars); // Don't really need to waste time clearing this string here - Token::Kind kind; - - if (lexingUnit) { - lexIdentifier(t.chars, false); - ASSERT(t.chars.size()); - kind = Token::unit; // unit - lexingUnit = false; - } else { - next: - char16 ch = reader.get(); - if (reader.getEof(ch)) { - endOfInput: - t.pos = reader.getPos() - 1; - kind = Token::end; - } else { - char16 ch2; - CharInfo chi(ch); - - switch (cGroup(chi)) { - case CharInfo::FormatGroup: - case CharInfo::WhiteGroup: - goto next; - - case CharInfo::IdGroup: - t.pos = reader.getPos() - 1; - readIdentifier: - { - reader.unget(); - String s; - bool hasEscape = lexIdentifier(s, false); - t.id = &world.identifiers[s]; - kind = hasEscape ? Token::identifier : t.id->tokenKind; - } - break; - - case CharInfo::NonIdGroup: - case CharInfo::IdContinueGroup: - t.pos = reader.getPos() - 1; - switch (ch) { - case '(': - kind = Token::openParenthesis; // ( - break; - case ')': - kind = Token::closeParenthesis; // ) - break; - case '[': - kind = Token::openBracket; // [ - break; - case ']': - kind = Token::closeBracket; // ] - break; - case '{': - kind = Token::openBrace; // { - break; - case '}': - kind = Token::closeBrace; // } - break; - case ',': - kind = Token::comma; // , - break; - case ';': - kind = Token::semicolon; // ; - break; - case '.': - kind = Token::dot; // . - ch2 = getChar(); - if (isASCIIDecimalDigit(ch2)) { - reader.setPos(t.pos); - goto number; // decimal point - } else if (ch2 == '.') { - kind = Token::doubleDot; // .. - if (testChar('.')) - kind = Token::tripleDot; // ... - } else - reader.unget(); - break; - case ':': - kind = Token::colon; // : - if (testChar(':')) - kind = Token::doubleColon; // :: - break; - case '#': - kind = Token::pound; // # - break; - case '@': - kind = Token::at; // @ - break; - case '?': - kind = Token::question; // ? - break; - - case '~': - kind = Token::complement; // ~ - break; - case '!': - kind = Token::logicalNot; // ! - if (testChar('=')) { - kind = Token::notEqual; // != - if (testChar('=')) - kind = Token::notIdentical; // !== - } - break; - - case '*': - kind = Token::times; // * *= - tryAssignment: - if (testChar('=')) - kind = Token::Kind(kind + Token::timesEquals - Token::times); - break; - - case '/': - kind = Token::divide; // / - ch = getChar(); - if (ch == '/') { // // comment - do { - ch = reader.get(); - if (reader.getEof(ch)) - goto endOfInput; - } while (!isLineBreak(ch)); - goto endOfLine; - } else if (ch == '*') { // /* comment */ - ch = 0; - do { - ch2 = ch; - ch = getChar(); - if (isLineBreak(ch)) { - reader.beginLine(); - t.lineBreak = true; - } else if (reader.getEof(ch)) - syntaxError("Unterminated /* comment"); - } while (ch != '/' || ch2 != '*'); - goto next; - } else { - reader.unget(); - if (preferRegExp) { // Regular expression - kind = Token::regExp; - lexRegExp(); - } else - goto tryAssignment; // /= - } - break; - - case '%': - kind = Token::modulo; // % - goto tryAssignment; // %= - - case '+': - kind = Token::plus; // + - if (testChar('+')) - kind = Token::increment; // ++ - else - goto tryAssignment; // += - break; - - case '-': - kind = Token::minus; // - - ch = getChar(); - if (ch == '-') - kind = Token::decrement; // -- - else if (ch == '>') - kind = Token::arrow; // -> - else { - reader.unget(); - goto tryAssignment; // -= - } - break; - - case '&': - kind = Token::bitwiseAnd; // & && &= &&= - logical: - if (testChar(ch)) - kind = Token::Kind(kind - Token::bitwiseAnd + Token::logicalAnd); - goto tryAssignment; - case '^': - kind = Token::bitwiseXor; // ^ ^^ ^= ^^= - goto logical; - case '|': - kind = Token::bitwiseOr; // | || |= ||= - goto logical; - - case '=': - kind = Token::assignment; // = - if (testChar('=')) { - kind = Token::equal; // == - if (testChar('=')) - kind = Token::identical; // === - } - break; - - case '<': - kind = Token::lessThan; // < - if (testChar('<')) { - kind = Token::leftShift; // << - goto tryAssignment; // <<= - } - comparison: - if (testChar('=')) // <= >= - kind = Token::Kind(kind + Token::lessThanOrEqual - Token::lessThan); - break; - case '>': - kind = Token::greaterThan; // > - if (testChar('>')) { - kind = Token::rightShift; // >> - if (testChar('>')) - kind = Token::logicalRightShift; // >>> - goto tryAssignment; // >>= >>>= - } - goto comparison; - - case '\\': - goto readIdentifier; // An identifier that starts with an escape - - case '\'': - case '"': - kind = Token::string; // 'string' "string" - lexString(t.chars, ch); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - reader.unget(); // Number - number: - kind = Token::number; - lexingUnit = lexNumeral(); - break; - - default: - syntaxError("Bad character"); - } - break; - - case CharInfo::LineBreakGroup: - endOfLine: - reader.beginLine(); - t.lineBreak = true; - goto next; - } - } - } - t.kind = kind; - #ifdef DEBUG - t.valid = true; - #endif -} - - - -// -// Parser Utilities -// - -const bool debugExprNodePrint = true; // Print extra parentheses around subexpressions? -const int32 basicIndent = 4; // Size of one level of statement indentation -const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement -const int32 varIndent = 2; // Indentation of var or const statement bindings -const int32 subexpressionIndent = 4; // Size of one level of expression indentation -const int32 functionHeaderIndent = 9; // Indentation of function signature -const int32 namespaceHeaderIndent = 4; // Indentation of class, interface, or namespace header - - -static const char functionPrefixNames[3][5] = {"", "get ", "set " }; - -// Print this onto f. name must be non-nil. -void JS::FunctionName::print(PrettyPrinter &f) const -{ - f << functionPrefixNames[prefix]; - f << name; -} - - -// Print this onto f. -void JS::VariableBinding::print(PrettyPrinter &f) const -{ - PrettyPrinter::Block b(f); -#ifdef NEW_PARSER - if (aliases) { - IdentifierList *id = aliases; - f << "| "; - while (id) { - f << "'"; - f << id->name; - f << "' "; - id = id->next; - } - } -#endif - if (name) - f << name; - PrettyPrinter::Indent i(f, subexpressionIndent); - if (type) { - f.fillBreak(0); - f << ": "; - f << type; - } - if (initializer) { - f.linearBreak(1); - f << "= "; - f << initializer; - } -} - - -// Print this onto f. If isConstructor is true, this is a constructor. -// If attributes is null, this is a function expression; if attributes is non-null, -// this is a function statement with the given attributes. -// When there is no function body, print a trailing semicolon unless noSemi is true. -void JS::FunctionDefinition::print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const -{ - PrettyPrinter::Block b(f); - if (attributes) - attributes->printAttributes(f); - f << (isConstructor ? "constructor" : "function"); - if (name) { - f << ' '; - FunctionName::print(f); - } - { - PrettyPrinter::Indent i(f, functionHeaderIndent); - f.fillBreak(0); - f << '('; - { - PrettyPrinter::Block b2(f); - const VariableBinding *p = parameters; - if (p) - while (true) { - if (p == restParameter) { - f << "..."; - if (p->name) - f << ' '; - } - p->print(f); - p = p->next; - if (!p) - break; - f << ','; - f.fillBreak(1); - } - f << ')'; - } - if (resultType) { - f.fillBreak(0); - f << ": "; - f << resultType; - } - } - if (body) { - bool loose = attributes != 0; - f.linearBreak(1, loose); - body->printBlock(f, loose); - } else - StmtNode::printSemi(f, noSemi); -} - - -// Print a comma-separated ExprList on to f. Since a method can't be called on nil, the list -// has at least one element. -void JS::ExprList::printCommaList(PrettyPrinter &f) const -{ - PrettyPrinter::Block b(f); - const ExprList *list = this; - while (true) { - f << list->expr; - list = list->next; - if (!list) - break; - f << ','; - f.fillBreak(1); - } -} - - -// If list is nil, do nothing. Otherwise, emit a linear line break of size 1, the name, a space, and the -// contents of list separated by commas. -void JS::ExprList::printOptionalCommaList(PrettyPrinter &f, const char *name, const ExprList *list) -{ - if (list) { - f.linearBreak(1); - f << name << ' '; - list->printCommaList(f); - } -} - - -// -// ExprNode -// - -const char *const JS::ExprNode::kindNames[kindsEnd] = { - "NIL", // none - 0, // identifier - 0, // number - 0, // string - 0, // regExp - "null", // Null - "true", // True - "false", // False - "this", // This - "super", // Super - - 0, // parentheses - 0, // numUnit - 0, // exprUnit - "::", // qualify - - 0, // objectLiteral - 0, // arrayLiteral - 0, // functionLiteral - - 0, // call - 0, // New - 0, // index - - ".", // dot - ".(", // dotParen - "@", // at - - "delete ", // Delete - "typeof ", // Typeof - "eval ", // Eval - "++ ", // preIncrement - "-- ", // preDecrement - " ++", // postIncrement - " --", // postDecrement - "+ ", // plus - "- ", // minus - "~ ", // complement - "! ", // logicalNot - - "+", // add - "-", // subtract - "*", // multiply - "/", // divide - "%", // modulo - "<<", // leftShift - ">>", // rightShift - ">>>", // logicalRightShift - "&", // bitwiseAnd - "^", // bitwiseXor - "|", // bitwiseOr - "&&", // logicalAnd - "^^", // logicalXor - "||", // logicalOr - - "==", // equal - "!=", // notEqual - "<", // lessThan - "<=", // lessThanOrEqual - ">", // greaterThan - ">=", // greaterThanOrEqual - "===", // identical - "!==", // notIdentical - "in", // In - "instanceof", // Instanceof - - "=", // assignment - "+=", // addEquals - "-=", // subtractEquals - "*=", // multiplyEquals - "/=", // divideEquals - "%=", // moduloEquals - "<<=", // leftShiftEquals - ">>=", // rightShiftEquals - ">>>=", // logicalRightShiftEquals - "&=", // bitwiseAndEquals - "^=", // bitwiseXorEquals - "|=", // bitwiseOrEquals - "&&=", // logicalAndEquals - "^^=", // logicalXorEquals - "||=", // logicalOrEquals - - "?", // conditional - "," // comma -}; - - -// Print this onto f. -void JS::ExprNode::print(PrettyPrinter &f) const -{ - f << kindName(kind); -} - -void JS::IdentifierExprNode::print(PrettyPrinter &f) const -{ - f << name; -} - -void JS::NumberExprNode::print(PrettyPrinter &f) const -{ - f << value; -} - -void JS::StringExprNode::print(PrettyPrinter &f) const -{ - quoteString(f, str, '"'); -} - -void JS::RegExpExprNode::print(PrettyPrinter &f) const -{ - f << '/' << re << '/' << flags; -} - -void JS::NumUnitExprNode::print(PrettyPrinter &f) const -{ - f << numStr; - StringExprNode::print(f); -} - -void JS::ExprUnitExprNode::print(PrettyPrinter &f) const -{ - f << op; - StringExprNode::print(f); -} - -void JS::FunctionExprNode::print(PrettyPrinter &f) const -{ - function.print(f, false, 0, false); -} - -void JS::PairListExprNode::print(PrettyPrinter &f) const -{ - char beginBracket; - char endBracket; - - switch (getKind()) { - case objectLiteral: - beginBracket = '{'; - endBracket = '}'; - break; - - case arrayLiteral: - case index: - beginBracket = '['; - endBracket = ']'; - break; - - case call: - case New: - beginBracket = '('; - endBracket = ')'; - break; - - default: - NOT_REACHED("Bad kind"); - return; - } - - f << beginBracket; - PrettyPrinter::Block b(f); - const ExprPairList *p = pairs; - if (p) - while (true) { - const ExprNode *field = p->field; - if (field) { - f << field << ':'; - f.fillBreak(0); - } - - const ExprNode *value = p->value; - if (value) - f << value; - - p = p->next; - if (!p) - break; - f << ','; - f.linearBreak(static_cast(field || value)); - } - f << endBracket; -} - -void JS::InvokeExprNode::print(PrettyPrinter &f) const -{ - PrettyPrinter::Block b(f); - if (hasKind(New)) - f << "new "; - f << op; - PrettyPrinter::Indent i(f, subexpressionIndent); - f.fillBreak(0); - PairListExprNode::print(f); -} - -void JS::UnaryExprNode::print(PrettyPrinter &f) const -{ - if (hasKind(parentheses)) { - f << '('; - f << op; - f << ')'; - } else { - if (debugExprNodePrint) - f << '('; - const char *name = kindName(getKind()); - if (hasKind(postIncrement) || hasKind(postDecrement)) { - f << op; - f << name; - } else { - f << name; - f << op; - } - if (debugExprNodePrint) - f << ')'; - } -} - -void JS::BinaryExprNode::print(PrettyPrinter &f) const -{ - if (debugExprNodePrint && !hasKind(qualify)) - f << '('; - PrettyPrinter::Block b(f); - f << op1; - uint32 nSpaces = hasKind(dot) || hasKind(dotParen) || hasKind(at) || hasKind(qualify) ? (uint32)0 : (uint32)1; - f.fillBreak(nSpaces); - f << kindName(getKind()); - f.fillBreak(nSpaces); - f << op2; - if (hasKind(dotParen)) - f << ')'; - if (debugExprNodePrint && !hasKind(qualify)) - f << ')'; -} - -void JS::TernaryExprNode::print(PrettyPrinter &f) const -{ - if (debugExprNodePrint) - f << '('; - PrettyPrinter::Block b(f); - f << op1; - f.fillBreak(1); - f << '?'; - f.fillBreak(1); - f << op2; - f.fillBreak(1); - f << ':'; - f.fillBreak(1); - f << op3; - if (debugExprNodePrint) - f << ')'; -} - - -// -// StmtNode -// - - -// Print statements on separate lines onto f. Do not print a line break after the last statement. -void JS::StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements) -{ - if (statements) { - PrettyPrinter::Block b(f); - while (true) { - const StmtNode *next = statements->next; - statements->print(f, !next); - statements = next; - if (!statements) - break; - f.requiredBreak(); - } - } -} - - -// Print statements as a block enclosed in curly braces onto f. -// If loose is false, do not insist on each statement being on a separate line; instead, -// make breaks between statements be linear breaks in the enclosing PrettyPrinter::Block scope. -// The caller must have placed this call inside a PrettyPrinter::Block scope. -void JS::StmtNode::printBlockStatements(PrettyPrinter &f, const StmtNode *statements, bool loose) -{ - f << '{'; - if (statements) { - { - PrettyPrinter::Indent i(f, basicIndent); - uint32 nSpaces = 0; - while (statements) { - if (statements->hasKind(Case)) { - PrettyPrinter::Indent i2(f, caseIndent - basicIndent); - f.linearBreak(nSpaces, loose); - statements->print(f, false); - } else { - f.linearBreak(nSpaces, loose); - statements->print(f, !statements->next); - } - statements = statements->next; - nSpaces = 1; - } - } - f.linearBreak(0, loose); - } else - f.fillBreak(0); - f << '}'; -} - - -// Print a closing statement semicolon onto f unless noSemi is true. -void JS::StmtNode::printSemi(PrettyPrinter &f, bool noSemi) -{ - if (!noSemi) - f << ';'; -} - - -// Print this as a substatement of a statement such as if or with. -// If this statement is a block without attributes, begin it on the current line and -// do not indent it -- the block itself will provide the indent. Otherwise, begin this -// statement on a new line and indent it. -// If continuation is non-nil, it specifies a continuation such as 'else' or the 'while' -// of a do-while statement. If this statement is a block without attributes, print a -// space and the continuation after the closing brace; otherwise print the continuation -// on a new line. -// If noSemi is true, do not print the semicolon unless it is required by the statement. -// The caller must have placed this call inside a PrettyPrinter::Block scope that encloses -// the containining statement. -void JS::StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation) const -{ - if (hasKind(block) && !static_cast(this)->attributes) { - f << ' '; - static_cast(this)->printBlock(f, true); - if (continuation) - f << ' ' << continuation; - } else { - { - PrettyPrinter::Indent i(f, basicIndent); - f.requiredBreak(); - this->print(f, noSemi); - } - if (continuation) { - f.requiredBreak(); - f << continuation; - } - } -} - - -// Print the attributes on a single line separated with and followed by a space. -void JS::AttributeStmtNode::printAttributes(PrettyPrinter &f) const -{ - for (const IdentifierList *a = attributes; a; a = a->next) - f << a->name << ' '; -} - - -// Print this block, including attributes, onto f. -// If loose is false, do not insist on each statement being on a separate line; instead, -// make breaks between statements be linear breaks in the enclosing PrettyPrinter::Block scope. -// The caller must have placed this call inside a PrettyPrinter::Block scope. -void JS::BlockStmtNode::printBlock(PrettyPrinter &f, bool loose) const -{ - printAttributes(f); - printBlockStatements(f, statements, loose); -} - - -// Print this onto f. -// If noSemi is true, do not print the trailing semicolon unless it is required by the statement. -void JS::StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const -{ - ASSERT(hasKind(empty)); - f << ';'; -} - -void JS::ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - const ExprNode *e = expr; - - switch (getKind()) { - case Case: - if (e) { - f << "case "; - f << e; - } else - f << "default"; - f << ':'; - break; - - case Return: - f << "return"; - if (e) { - f << ' '; - goto showExpr; - } else - goto showSemicolon; - - case Throw: - f << "throw "; - case expression: - showExpr: - f << e; - showSemicolon: - printSemi(f, noSemi); - break; - - default: - NOT_REACHED("Bad kind"); - } -} - -void JS::DebuggerStmtNode::print(PrettyPrinter &f, bool) const -{ - f << "debugger;"; -} - -void JS::BlockStmtNode::print(PrettyPrinter &f, bool) const -{ - PrettyPrinter::Block b(f, 0); - printBlock(f, true); -} - -void JS::LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - PrettyPrinter::Block b(f, basicIndent); - f << name << ':'; - f.linearBreak(1); - stmt->print(f, noSemi); -} - -void JS::UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - PrettyPrinter::Block b(f, 0); - printContents(f, noSemi); -} - -// Same as print except that uses the caller's PrettyPrinter::Block. -void JS::UnaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const -{ - ASSERT(stmt); - const char *kindName = 0; - - switch (getKind()) { - case If: - kindName = "if"; - break; - - case While: - kindName = "while"; - break; - - case DoWhile: - f << "do"; - stmt->printSubstatement(f, true, "while ("); - f << expr << ')'; - printSemi(f, noSemi); - return; - - case With: - kindName = "with"; - break; - - default: - NOT_REACHED("Bad kind"); - } - - f << kindName << " ("; - f << expr << ')'; - stmt->printSubstatement(f, noSemi); -} - -void JS::BinaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const -{ - ASSERT(stmt && stmt2 && hasKind(IfElse)); - - f << "if ("; - f << expr << ')'; - stmt->printSubstatement(f, true, "else"); - if (stmt2->hasKind(If) || stmt2->hasKind(IfElse)) { - f << ' '; - static_cast(stmt2)->printContents(f, noSemi); - } else - stmt2->printSubstatement(f, noSemi); -} - -void JS::ForStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - ASSERT(stmt && (hasKind(For) || hasKind(ForIn))); - - PrettyPrinter::Block b(f, 0); - f << "for ("; - { - PrettyPrinter::Block b2(f); - if (initializer) - initializer->print(f, true); - if (hasKind(ForIn)) { - f.fillBreak(1); - f << "in"; - f.fillBreak(1); - ASSERT(expr2 && !expr3); - f << expr2; - } else { - f << ';'; - if (expr2) { - f.linearBreak(1); - f << expr2; - } - f << ';'; - if (expr3) { - f.linearBreak(1); - f << expr3; - } - } - f << ')'; - } - stmt->printSubstatement(f, noSemi); -} - -void JS::SwitchStmtNode::print(PrettyPrinter &f, bool) const -{ - PrettyPrinter::Block b(f); - f << "switch ("; - f << expr << ") "; - printBlockStatements(f, statements, true); -} - -void JS::GoStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - const char *kindName = 0; - - switch (getKind()) { - case Break: - kindName = "break"; - break; - - case Continue: - kindName = "continue"; - break; - - default: - NOT_REACHED("Bad kind"); - } - - f << kindName; - if (name) - f << " " << *name; - printSemi(f, noSemi); -} - -void JS::TryStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - PrettyPrinter::Block b(f, 0); - f << "try"; - const StmtNode *s = stmt; - for (const CatchClause *c = catches; c; c = c->next) { - s->printSubstatement(f, true, "catch ("); - PrettyPrinter::Block b2(f); - f << c->name; - ExprNode *t = c->type; - if (t) { - f << ':'; - f.linearBreak(1); - f << t; - } - f << ')'; - s = c->stmt; - } - if (finally) { - s->printSubstatement(f, true, "finally"); - s = finally; - } - s->printSubstatement(f, noSemi); -} - -void JS::VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - printAttributes(f); - ASSERT(hasKind(Const) || hasKind(Var)); - f << (hasKind(Const) ? "const" : "var"); - { - PrettyPrinter::Block b(f, basicIndent); - const VariableBinding *binding = bindings; - if (binding) - while (true) { - f.linearBreak(1); - binding->print(f); - binding = binding->next; - if (!binding) - break; - f << ','; - } - } - printSemi(f, noSemi); -} - -void JS::FunctionStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - function.print(f, hasKind(Constructor), this, noSemi); -} - -void JS::NamespaceStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - printAttributes(f); - ASSERT(hasKind(Namespace)); - - PrettyPrinter::Block b(f, namespaceHeaderIndent); - f << "namespace "; - f << name; - ExprList::printOptionalCommaList(f, "extends", supers); - printSemi(f, noSemi); -} - -void JS::ClassStmtNode::print(PrettyPrinter &f, bool noSemi) const -{ - printAttributes(f); - ASSERT(hasKind(Class) || hasKind(Interface)); - - { - PrettyPrinter::Block b(f, namespaceHeaderIndent); - const char *keyword; - const char *superlistKeyword; - if (hasKind(Class)) { - keyword = "class "; - superlistKeyword = "implements"; - } else { - keyword = "interface "; - superlistKeyword = "extends"; - } - f << keyword; - f << name; - if (superclass) { - f.linearBreak(1); - f << "extends "; - f << superclass; - } - ExprList::printOptionalCommaList(f, superlistKeyword, supers); - } - if (body) { - f.requiredBreak(); - body->printBlock(f, true); - } else - printSemi(f, noSemi); -} - - // // Parser // -JS::NodeFactory * JS::NodeFactory::state; - -// Create a new Parser for parsing the provided source code, interning identifiers, keywords, and regular -// expressions in the designated world, and allocating the parse tree in the designated arena. -JS::Parser::Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum): - lexer(world, source, sourceLocation, initialLineNum), arena(arena), lineBreaksSignificant(true) +namespace JavaScript { - NodeFactory::Init(arena); -} + NodeFactory *NodeFactory::state; + +// Create a new Parser for parsing the provided source code, interning +// identifiers, keywords, and regular expressions in the designated world, +// and allocating the parse tree in the designated arena. + Parser::Parser(World &world, Arena &arena, const String &source, + const String &sourceLocation, uint32 initialLineNum): + lexer(world, source, sourceLocation, initialLineNum), + arena(arena), lineBreaksSignificant(true) + { + NodeFactory::Init(arena); + } // Report a syntax error at the backUp-th last token read by the Lexer. -// In other words, if backUp is 0, the error is at the next token to be read by the Lexer (which -// must have been peeked already); if backUp is 1, the error is at the last token read by the Lexer, -// and so forth. -void JS::Parser::syntaxError(const char *message, uint backUp) -{ - syntaxError(widenCString(message), backUp); -} +// In other words, if backUp is 0, the error is at the next token to be read +// by the Lexer (which must have been peeked already); if backUp is 1, the +// error is at the last token read by the Lexer, and so forth. + void + Parser::syntaxError(const char *message, uint backUp) + { + syntaxError(widenCString(message), backUp); + } // Same as above, but the error message is already a String. -void JS::Parser::syntaxError(const String &message, uint backUp) -{ - while (backUp--) - lexer.unget(); - getReader().error(Exception::syntaxError, message, lexer.getPos()); -} + void + Parser::syntaxError(const String &message, uint backUp) + { + while (backUp--) + lexer.unget(); + getReader().error(Exception::syntaxError, message, lexer.getPos()); + } -// Get the next token using the given preferRegExp setting. If that token's kind matches -// the given kind, consume that token and return it. Otherwise throw a syntax error. -const JS::Token &JS::Parser::require(bool preferRegExp, Token::Kind kind) -{ - const Token &t = lexer.get(preferRegExp); - if (!t.hasKind(kind)) { - String message; - bool special = Token::isSpecialKind(kind); - - if (special) - message += '\''; - message += Token::kindName(kind); - if (special) - message += '\''; - message += " expected"; - syntaxError(message); - } - return t; -} - +// Get the next token using the given preferRegExp setting. If that token's +// kind matches the given kind, consume that token and return it. Otherwise +// throw a syntax error. + const Token & + Parser::require(bool preferRegExp, Token::Kind kind) + { + const Token &t = lexer.get(preferRegExp); + if (!t.hasKind(kind)) { + String message; + bool special = Token::isSpecialKind(kind); + + if (special) + message += '\''; + message += Token::kindName(kind); + if (special) + message += '\''; + message += " expected"; + syntaxError(message); + } + return t; + } // Copy the Token's chars into the current arena and return the resulting copy. -inline JS::String &JS::Parser::copyTokenChars(const Token &t) -{ - return newArenaString(arena, t.getChars()); -} - - + inline String & + Parser::copyTokenChars(const Token &t) + { + return newArenaString(arena, t.getChars()); + } // If t is an Identifier, return a new IdentifierExprNode corresponding to t. // Otherwise, return null. -JS::ExprNode *JS::Parser::makeIdentifierExpression(const Token &t) const -{ - if (t.hasIdentifierKind()) - return new(arena) IdentifierExprNode(t); - return 0; -} - + ExprNode * + Parser::makeIdentifierExpression(const Token &t) const + { + if (t.hasIdentifierKind()) + return new(arena) IdentifierExprNode(t); + return 0; + } // An identifier or parenthesized expression has just been parsed into e. -// If it is followed by one or more ::'s followed by identifiers, construct the appropriate -// qualify parse node and return it and set foundQualifiers to true. If no :: -// is found, return e and set foundQualifiers to false. -// After parseIdentifierQualifiers finishes, the next token might have been peeked with the given preferRegExp setting. -JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp) -{ - const Token *tDoubleColon = lexer.eat(preferRegExp, Token::doubleColon); - if (!tDoubleColon) { - foundQualifiers = false; - return e; - } +// If it is followed by one or more ::'s followed by identifiers, construct +// the appropriate qualify parse node and return it and set foundQualifiers +// to true. If no :: is found, return e and set foundQualifiers to false. +// After parseIdentifierQualifiers finishes, the next token might have been +// peeked with the given preferRegExp setting. + ExprNode * + Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, + bool preferRegExp) + { + const Token *tDoubleColon = lexer.eat(preferRegExp, + Token::doubleColon); + if (!tDoubleColon) { + foundQualifiers = false; + return e; + } - foundQualifiers = true; - checkStackSize(); - uint32 pos = tDoubleColon->getPos(); - return new(arena) BinaryExprNode(pos, ExprNode::qualify, e, parseQualifiedIdentifier(lexer.get(true), preferRegExp)); -} + foundQualifiers = true; + checkStackSize(); + uint32 pos = tDoubleColon->getPos(); + return new(arena) BinaryExprNode(pos, ExprNode::qualify, e, + parseQualifiedIdentifier(lexer.get(true), + preferRegExp)); + } + +// An opening parenthesis has just been parsed into tParen. Finish parsing a +// ParenthesizedExpression. +// If it is followed by one or more ::'s followed by identifiers, construct +// the appropriate qualify parse node and return it and set foundQualifiers to +// true. If no :: is found, return the ParenthesizedExpression and set +// foundQualifiers to false. After parseParenthesesAndIdentifierQualifiers +// finishes, the next token might have been peeked with the given preferRegExp +// setting. + ExprNode * + Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, + bool &foundQualifiers, + bool preferRegExp) + { + uint32 pos = tParen.getPos(); + ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, + parseExpression(false)); + require(false, Token::closeParenthesis); + return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); + } + +// Parse and return a qualifiedIdentifier. The first token has already been +// parsed and is in t. If the second token was peeked, it should be have been +// done with the given preferRegExp setting. After parseQualifiedIdentifier +// finishes, the next token might have been peeked with the given +// preferRegExp setting. + ExprNode * + Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp) + { + bool foundQualifiers; + ExprNode *e = makeIdentifierExpression(t); + if (e) + return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); + if (t.hasKind(Token::openParenthesis)) { + e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, + preferRegExp); + goto checkQualifiers; + } + if (t.hasKind(Token::Super)) { + e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), + ExprNode::Super), + foundQualifiers, preferRegExp); + goto checkQualifiers; + } + if (t.hasKind(Token::Public) || t.hasKind(Token::Package) || + t.hasKind(Token::Private)) { + e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), + foundQualifiers, preferRegExp); + checkQualifiers: + if (!foundQualifiers) + syntaxError("'::' expected", 0); + return e; + } + syntaxError("Identifier or '(' expected"); + return 0; // Unreachable code here just to shut up compiler warnings + } + +// Parse and return an arrayLiteral. The opening bracket has already been +// read into initialToken. + PairListExprNode * + Parser::parseArrayLiteral(const Token &initialToken) + { + uint32 initialPos = initialToken.getPos(); + NodeQueue elements; + + while (true) { + ExprNode *element = 0; + const Token &t = lexer.peek(true); + if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket)) + lexer.redesignate(false); // Safe: neither ',' + // nor '}' starts with a slash. + else + element = parseAssignmentExpression(false); + elements += new(arena) ExprPairList(0, element); + + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(Token::closeBracket)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); + } + return new(arena) PairListExprNode(initialPos, ExprNode::arrayLiteral, + elements.first); + } -// An opening parenthesis has just been parsed into tParen. Finish parsing a ParenthesizedExpression. -// If it is followed by one or more ::'s followed by identifiers, construct the appropriate -// qualify parse node and return it and set foundQualifiers to true. If no :: -// is found, return the ParenthesizedExpression and set foundQualifiers to false. -// After parseParenthesesAndIdentifierQualifiers finishes, the next token might have been peeked with -// the given preferRegExp setting. -JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp) -{ - uint32 pos = tParen.getPos(); - ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, parseExpression(false)); - require(false, Token::closeParenthesis); - return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); -} +// Parse and return an objectLiteral. The opening brace has already been +// read into initialToken. + PairListExprNode * + Parser::parseObjectLiteral(const Token &initialToken) + { + uint32 initialPos = initialToken.getPos(); + NodeQueue elements; + + if (!lexer.eat(true, Token::closeBrace)) + while (true) { + const Token &t = lexer.get(true); + ExprNode *field; + if (t.hasIdentifierKind() || + t.hasKind(Token::openParenthesis) || + t.hasKind(Token::Super) || t.hasKind(Token::Public) || + t.hasKind(Token::Package) || t.hasKind(Token::Private)) + field = parseQualifiedIdentifier(t, false); + else if (t.hasKind(Token::string)) { + field = NodeFactory::LiteralString(t.getPos(), + ExprNode::string, + copyTokenChars(t)); + } + else if (t.hasKind(Token::number)) + field = new(arena) NumberExprNode(t); + else { + syntaxError("Field name expected"); + // Unreachable code here just to shut up compiler warnings + field = 0; + } + require(false, Token::colon); + elements += NodeFactory::LiteralField(field, + parseAssignmentExpression(false)); - -// Parse and return a qualifiedIdentifier. The first token has already been parsed and is in t. -// If the second token was peeked, it should be have been done with the given preferRegExp setting. -// After parseQualifiedIdentifier finishes, the next token might have been peeked with the given preferRegExp setting. -JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp) -{ - bool foundQualifiers; - ExprNode *e = makeIdentifierExpression(t); - if (e) - return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); - if (t.hasKind(Token::openParenthesis)) { - e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, preferRegExp); - goto checkQualifiers; - } - if (t.hasKind(Token::Super)) { - e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), ExprNode::Super), foundQualifiers, preferRegExp); - goto checkQualifiers; - } - if (t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private)) { - e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp); - checkQualifiers: - if (!foundQualifiers) - syntaxError("'::' expected", 0); - return e; - } - syntaxError("Identifier or '(' expected"); - return 0; // Unreachable code here just to shut up compiler warnings -} - - -// Parse and return an arrayLiteral. The opening bracket has already been read into initialToken. -JS::PairListExprNode *JS::Parser::parseArrayLiteral(const Token &initialToken) -{ - uint32 initialPos = initialToken.getPos(); - NodeQueue elements; - - while (true) { - ExprNode *element = 0; - const Token &t = lexer.peek(true); - if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket)) - lexer.redesignate(false); // Safe: neither ',' nor '}' starts with a slash. - else - element = parseAssignmentExpression(false); - elements += new(arena) ExprPairList(0, element); - - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(Token::closeBracket)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } - return new(arena) PairListExprNode(initialPos, ExprNode::arrayLiteral, elements.first); -} - - -// Parse and return an objectLiteral. The opening brace has already been read into initialToken. -JS::PairListExprNode *JS::Parser::parseObjectLiteral(const Token &initialToken) -{ - uint32 initialPos = initialToken.getPos(); - NodeQueue elements; - - if (!lexer.eat(true, Token::closeBrace)) - while (true) { - const Token &t = lexer.get(true); - ExprNode *field; - if (t.hasIdentifierKind() || t.hasKind(Token::openParenthesis) || t.hasKind(Token::Super) || - t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private)) - field = parseQualifiedIdentifier(t, false); - else if (t.hasKind(Token::string)) { - field = NodeFactory::LiteralString(t.getPos(),ExprNode::string,copyTokenChars(t)); + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(Token::closeBrace)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); } - else if (t.hasKind(Token::number)) - field = new(arena) NumberExprNode(t); - else { - syntaxError("Field name expected"); - field = 0; // Unreachable code here just to shut up compiler warnings - } - require(false, Token::colon); - elements += NodeFactory::LiteralField(field, parseAssignmentExpression(false)); - - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(Token::closeBrace)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } - return new(arena) PairListExprNode(initialPos, ExprNode::objectLiteral, elements.first); + return new(arena) PairListExprNode(initialPos, + ExprNode::objectLiteral, + elements.first); } - // Parse and return a PrimaryExpression. -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parsePrimaryExpression finishes, the next token might have been peeked with preferRegExp set to false. -JS::ExprNode *JS::Parser::parsePrimaryExpression() -{ - ExprNode *e; - ExprNode::Kind eKind; - - const Token &t = lexer.get(true); - switch (t.getKind()) { - case Token::Null: - eKind = ExprNode::Null; - goto makeExprNode; - - case Token::True: - eKind = ExprNode::True; - goto makeExprNode; - - case Token::False: - eKind = ExprNode::False; - goto makeExprNode; - - case Token::This: - eKind = ExprNode::This; - goto makeExprNode; - - case Token::Super: - eKind = ExprNode::Super; - if (lexer.peek(false).hasKind(Token::doubleColon)) - goto makeQualifiedIdentifierNode; - makeExprNode: - e = new(arena) ExprNode(t.getPos(), eKind); - break; - - case Token::Public: - if (lexer.peek(false).hasKind(Token::doubleColon)) - goto makeQualifiedIdentifierNode; - e = new(arena) IdentifierExprNode(t); - break; - - case Token::number: - { - const Token &tUnit = lexer.peek(false); - if (!lineBreakBefore(tUnit) && (tUnit.hasKind(Token::unit) || tUnit.hasKind(Token::string))) { - lexer.get(false); - e = new(arena) NumUnitExprNode(t.getPos(), ExprNode::numUnit, copyTokenChars(t), t.getValue(), copyTokenChars(tUnit)); - } else - e = new(arena) NumberExprNode(t); - } - break; - - case Token::string: - e = NodeFactory::LiteralString(t.getPos(),ExprNode::string,copyTokenChars(t)); - break; - - case Token::regExp: - e = new(arena) RegExpExprNode(t.getPos(), ExprNode::regExp, t.getIdentifier(), copyTokenChars(t)); - break; - - case Token::Package: - case Token::Private: - case CASE_TOKEN_NONRESERVED: - makeQualifiedIdentifierNode: - e = parseQualifiedIdentifier(t, false); - break; - - case Token::openParenthesis: - { - bool foundQualifiers; - e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, false); - if (!foundQualifiers) { - const Token &tUnit = lexer.peek(false); - if (!lineBreakBefore(tUnit) && tUnit.hasKind(Token::string)) { - lexer.get(false); - e = new(arena) ExprUnitExprNode(t.getPos(), ExprNode::exprUnit, e, copyTokenChars(tUnit)); - } - } - } - break; - - case Token::openBracket: - e = parseArrayLiteral(t); - break; - - case Token::openBrace: - e = parseObjectLiteral(t); - break; - - case Token::Function: - { - FunctionExprNode *f = new(arena) FunctionExprNode(t.getPos()); - const Token &t2 = lexer.get(true); - f->function.prefix = FunctionName::normal; - if (!(f->function.name = makeIdentifierExpression(t2))) - lexer.unget(); - parseFunctionSignature(f->function); - f->function.body = parseBody(0); - e = f; - } - break; - - default: - syntaxError("Expression expected"); - e = 0; // Unreachable code here just to shut up compiler warnings - } - - return e; -} - - -// Parse a . or @ followed by a QualifiedIdentifier or ParenthesizedExpression and return -// the resulting BinaryExprNode. Use kind if a QualifiedIdentifier was found or parenKind -// if a ParenthesizedExpression was found. +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. After parsePrimaryExpression finishes, the next +// token might have been peeked with preferRegExp set to false. + ExprNode * + Parser::parsePrimaryExpression() + { + ExprNode *e; + ExprNode::Kind eKind; + + const Token &t = lexer.get(true); + switch (t.getKind()) { + case Token::Null: + eKind = ExprNode::Null; + goto makeExprNode; + + case Token::True: + eKind = ExprNode::True; + goto makeExprNode; + + case Token::False: + eKind = ExprNode::False; + goto makeExprNode; + + case Token::This: + eKind = ExprNode::This; + goto makeExprNode; + + case Token::Super: + eKind = ExprNode::Super; + if (lexer.peek(false).hasKind(Token::doubleColon)) + goto makeQualifiedIdentifierNode; + makeExprNode: + e = new(arena) ExprNode(t.getPos(), eKind); + break; + + case Token::Public: + if (lexer.peek(false).hasKind(Token::doubleColon)) + goto makeQualifiedIdentifierNode; + e = new(arena) IdentifierExprNode(t); + break; + + case Token::number: + { + const Token &tUnit = lexer.peek(false); + if (!lineBreakBefore(tUnit) && + (tUnit.hasKind(Token::unit) || + tUnit.hasKind(Token::string))) { + lexer.get(false); + e = new(arena) NumUnitExprNode(t.getPos(), + ExprNode::numUnit, + copyTokenChars(t), + t.getValue(), + copyTokenChars(tUnit)); + } else + e = new(arena) NumberExprNode(t); + } + break; + + case Token::string: + e = NodeFactory::LiteralString(t.getPos(), ExprNode::string, + copyTokenChars(t)); + break; + + case Token::regExp: + e = new(arena) RegExpExprNode(t.getPos(), ExprNode::regExp, + t.getIdentifier(), + copyTokenChars(t)); + break; + + case Token::Package: + case Token::Private: + case CASE_TOKEN_NONRESERVED: + makeQualifiedIdentifierNode: + e = parseQualifiedIdentifier(t, false); + break; + + case Token::openParenthesis: + { + bool foundQualifiers; + e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, + false); + if (!foundQualifiers) { + const Token &tUnit = lexer.peek(false); + if (!lineBreakBefore(tUnit) && + tUnit.hasKind(Token::string)) { + lexer.get(false); + e = new(arena) ExprUnitExprNode(t.getPos(), + ExprNode::exprUnit, e, + copyTokenChars(tUnit)); + } + } + } + break; + + case Token::openBracket: + e = parseArrayLiteral(t); + break; + + case Token::openBrace: + e = parseObjectLiteral(t); + break; + + case Token::Function: + { + FunctionExprNode *f = new(arena) FunctionExprNode(t.getPos()); + const Token &t2 = lexer.get(true); + f->function.prefix = FunctionName::normal; + if (!(f->function.name = makeIdentifierExpression(t2))) + lexer.unget(); + parseFunctionSignature(f->function); + f->function.body = parseBody(0); + e = f; + } + break; + + default: + syntaxError("Expression expected"); + // Unreachable code here just to shut up compiler warnings + e = 0; + } + + return e; + } + + +// Parse a . or @ followed by a QualifiedIdentifier or ParenthesizedExpression +// and return the resulting BinaryExprNode. Use kind if a QualifiedIdentifier +// was found or parenKind if a ParenthesizedExpression was found. // tOperator is the . or @ token. target is the first operand. -JS::BinaryExprNode *JS::Parser::parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind) -{ - uint32 pos = tOperator.getPos(); - ExprNode *member; - const Token &t2 = lexer.get(true); - if (t2.hasKind(Token::openParenthesis)) { - bool foundQualifiers; - member = parseParenthesesAndIdentifierQualifiers(t2, foundQualifiers, false); - if (!foundQualifiers) - kind = parenKind; - } else - member = parseQualifiedIdentifier(t2, false); - return new(arena) BinaryExprNode(pos, kind, target, member); -} + BinaryExprNode * + Parser::parseMember(ExprNode *target, const Token &tOperator, + ExprNode::Kind kind, ExprNode::Kind parenKind) + { + uint32 pos = tOperator.getPos(); + ExprNode *member; + const Token &t2 = lexer.get(true); + if (t2.hasKind(Token::openParenthesis)) { + bool foundQualifiers; + member = parseParenthesesAndIdentifierQualifiers(t2, + foundQualifiers, + false); + if (!foundQualifiers) + kind = parenKind; + } else + member = parseQualifiedIdentifier(t2, false); + return new(arena) BinaryExprNode(pos, kind, target, member); + } + - -// Parse an ArgumentsList followed by a closing parenthesis or bracket and return -// the resulting InvokeExprNode. The target function, indexed object, or created class -// is supplied. The opening parenthesis or bracket has already been read. +// Parse an ArgumentsList followed by a closing parenthesis or bracket and +// return the resulting InvokeExprNode. The target function, indexed object, +// or created class is supplied. The opening parenthesis or bracket has +// already been read. // pos is the position to use for the InvokeExprNode. -JS::InvokeExprNode *JS::Parser::parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind) -{ - NodeQueue arguments; - bool hasNamedArgument = false; - + InvokeExprNode * + Parser::parseInvoke(ExprNode *target, uint32 pos, + Token::Kind closingTokenKind, + ExprNode::Kind invokeKind) + { + NodeQueue arguments; + #ifdef NEW_PARSER - parseArgumentList(arguments); - match(closingTokenKind); + parseArgumentList(arguments); + match(closingTokenKind); #else - if (!lexer.eat(true, closingTokenKind)) - while (true) { - ExprNode *field = 0; - ExprNode *value = parseAssignmentExpression(false); - if (lexer.eat(false, Token::colon)) { - field = value; - if (!ExprNode::isFieldKind(field->getKind())) - syntaxError("Argument name must be an identifier, string, or number"); - hasNamedArgument = true; - value = parseAssignmentExpression(false); - } else if (hasNamedArgument) - syntaxError("Unnamed argument cannot follow named argument", 0); - arguments += new(arena) ExprPairList(field, value); + bool hasNamedArgument = false; - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(closingTokenKind)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } + if (!lexer.eat(true, closingTokenKind)) + while (true) { + ExprNode *field = 0; + ExprNode *value = parseAssignmentExpression(false); + if (lexer.eat(false, Token::colon)) { + field = value; + if (!ExprNode::isFieldKind(field->getKind())) + syntaxError("Argument name must be an identifier, " + "string, or number"); + hasNamedArgument = true; + value = parseAssignmentExpression(false); + } else if (hasNamedArgument) + syntaxError("Unnamed argument cannot follow named " + "argument", 0); + arguments += new(arena) ExprPairList(field, value); + + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(closingTokenKind)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); + } #endif - return new(arena) InvokeExprNode(pos, invokeKind, target, arguments.first); -} - + return new(arena) InvokeExprNode(pos, invokeKind, target, + arguments.first); + } // Parse and return a PostfixExpression. -// If newExpression is true, this expression is immediately preceded by 'new', so don't allow -// call, postincrement, or postdecrement operators on it. -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parsePostfixExpression finishes, the next token might have been peeked with preferRegExp set to false. -JS::ExprNode *JS::Parser::parsePostfixExpression(bool newExpression) -{ - ExprNode *e; - - const Token *tNew = lexer.eat(true, Token::New); - if (tNew) { - checkStackSize(); - uint32 posNew = tNew->getPos(); - e = parsePostfixExpression(true); - if (lexer.eat(false, Token::openParenthesis)) - e = parseInvoke(e, posNew, Token::closeParenthesis, ExprNode::New); - else - e = new(arena) InvokeExprNode(posNew, ExprNode::New, e, 0); - } else - e = parsePrimaryExpression(); - - while (true) { - ExprNode::Kind eKind; - const Token &t = lexer.get(false); - switch (t.getKind()) { - case Token::openParenthesis: - if (newExpression) - goto other; - e = parseInvoke(e, t.getPos(), Token::closeParenthesis, ExprNode::call); - break; - - case Token::openBracket: - e = parseInvoke(e, t.getPos(), Token::closeBracket, ExprNode::index); - break; - - case Token::dot: - e = parseMember(e, t, ExprNode::dot, ExprNode::dotParen); - break; - - case Token::at: - e = parseMember(e, t, ExprNode::at, ExprNode::at); - break; - - case Token::increment: - eKind = ExprNode::postIncrement; - incDec: - if (newExpression || lineBreakBefore(t)) - goto other; - e = new(arena) UnaryExprNode(t.getPos(), eKind, e); - break; - - case Token::decrement: - eKind = ExprNode::postDecrement; - goto incDec; - - default: - other: - lexer.unget(); - return e; - } - } -} - - -// Ensure that e is a postfix expression. If not, throw a syntax error on the current token. -void JS::Parser::ensurePostfix(const ExprNode *e) -{ - ASSERT(e); - if (!e->isPostfix()) - syntaxError("Only a postfix expression can be used as the result of an assignment; enclose this expression in parentheses", 0); -} - +// If newExpression is true, this expression is immediately preceded by 'new', +// so don't allow call, postincrement, or postdecrement operators on it. +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. After parsePostfixExpression finishes, the next +// token might have been peeked with preferRegExp set to false. + ExprNode * + Parser::parsePostfixExpression(bool newExpression) + { + ExprNode *e; + + const Token *tNew = lexer.eat(true, Token::New); + if (tNew) { + checkStackSize(); + uint32 posNew = tNew->getPos(); + e = parsePostfixExpression(true); + if (lexer.eat(false, Token::openParenthesis)) + e = parseInvoke(e, posNew, Token::closeParenthesis, + ExprNode::New); + else + e = new(arena) InvokeExprNode(posNew, ExprNode::New, e, 0); + } else + e = parsePrimaryExpression(); + + while (true) { + ExprNode::Kind eKind; + const Token &t = lexer.get(false); + switch (t.getKind()) { + case Token::openParenthesis: + if (newExpression) + goto other; + e = parseInvoke(e, t.getPos(), Token::closeParenthesis, + ExprNode::call); + break; + + case Token::openBracket: + e = parseInvoke(e, t.getPos(), Token::closeBracket, + ExprNode::index); + break; + + case Token::dot: + if (lexer.eat(true, Token::Class)) { + e = new(arena) UnaryExprNode(t.getPos(), + ExprNode::dotClass, e); + } else + e = parseMember(e, t, ExprNode::dot, + ExprNode::dotParen); + break; + + case Token::at: + e = parseMember(e, t, ExprNode::at, ExprNode::at); + break; + + case Token::increment: + eKind = ExprNode::postIncrement; + incDec: + if (newExpression || lineBreakBefore(t)) + goto other; + e = new(arena) UnaryExprNode(t.getPos(), eKind, e); + break; + + case Token::decrement: + eKind = ExprNode::postDecrement; + goto incDec; + + default: + other: + lexer.unget(); + return e; + } + } + } + +// Ensure that e is a postfix expression. If not, throw a syntax error on +// the current token. + void + Parser::ensurePostfix(const ExprNode *e) + { + ASSERT(e); + if (!e->isPostfix()) + syntaxError("Only a postfix expression can be used as the result " + "of an assignment; enclose this expression in " + "parentheses", 0); + } // Parse and return a UnaryExpression. -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseUnaryExpression finishes, the next token might have been peeked with preferRegExp set to false. -JS::ExprNode *JS::Parser::parseUnaryExpression() -{ - ExprNode::Kind eKind; - ExprNode *e; +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseUnaryExpression finishes, the next token might have been peeked +// with preferRegExp set to false. + ExprNode * + Parser::parseUnaryExpression() + { + ExprNode::Kind eKind; + ExprNode *e; - const Token &t = lexer.peek(true); - uint32 pos = t.getPos(); - switch (t.getKind()) { - case Token::Delete: - eKind = ExprNode::Delete; - goto getPostfixExpression; + const Token &t = lexer.peek(true); + uint32 pos = t.getPos(); + switch (t.getKind()) { + case Token::Delete: + eKind = ExprNode::Delete; + goto getPostfixExpression; + + case Token::increment: + eKind = ExprNode::preIncrement; + goto getPostfixExpression; + + case Token::decrement: + eKind = ExprNode::preDecrement; + getPostfixExpression: + lexer.get(true); + e = parsePostfixExpression(); + break; + + case Token::Typeof: + eKind = ExprNode::Typeof; + goto getUnaryExpression; + + case Token::Eval: + eKind = ExprNode::Eval; + goto getUnaryExpression; - case Token::increment: - eKind = ExprNode::preIncrement; - goto getPostfixExpression; + case Token::plus: + eKind = ExprNode::plus; + goto getUnaryExpression; + + case Token::minus: + eKind = ExprNode::minus; + goto getUnaryExpression; + + case Token::complement: + eKind = ExprNode::complement; + goto getUnaryExpression; + + case Token::logicalNot: + eKind = ExprNode::logicalNot; + getUnaryExpression: + lexer.get(true); + checkStackSize(); + e = parseUnaryExpression(); + break; + + default: + return parsePostfixExpression(); + } + return new(arena) UnaryExprNode(pos, eKind, e); + } + + + const Parser::BinaryOperatorInfo + Parser::tokenBinaryOperatorInfos[Token::kindsEnd] = { + + // Special - case Token::decrement: - eKind = ExprNode::preDecrement; - getPostfixExpression: - lexer.get(true); - e = parsePostfixExpression(); - break; + {ExprNode::none, pExpression, pNone}, // end + {ExprNode::none, pExpression, pNone}, // Token::number + {ExprNode::none, pExpression, pNone}, // Token::string + {ExprNode::none, pExpression, pNone}, // Token::unit + {ExprNode::none, pExpression, pNone}, // Token::regExp + + // Punctuators + + {ExprNode::none, pExpression, pNone}, // Token::openParenthesis + {ExprNode::none, pExpression, pNone}, // Token::closeParenthesis + {ExprNode::none, pExpression, pNone}, // Token::openBracket + {ExprNode::none, pExpression, pNone}, // Token::closeBracket + {ExprNode::none, pExpression, pNone}, // Token::openBrace + {ExprNode::none, pExpression, pNone}, // Token::closeBrace + {ExprNode::comma, pExpression, pExpression}, // Token::comma + {ExprNode::none, pExpression, pNone}, // Token::semicolon + {ExprNode::none, pExpression, pNone}, // Token::dot + {ExprNode::none, pExpression, pNone}, // Token::doubleDot + {ExprNode::none, pExpression, pNone}, // Token::tripleDot + {ExprNode::none, pExpression, pNone}, // Token::arrow + {ExprNode::none, pExpression, pNone}, // Token::colon + {ExprNode::none, pExpression, pNone}, // Token::doubleColon + {ExprNode::none, pExpression, pNone}, // Token::pound + {ExprNode::none, pExpression, pNone}, // Token::at + {ExprNode::none, pExpression, pNone}, // Token::increment + {ExprNode::none, pExpression, pNone}, // Token::decrement + {ExprNode::none, pExpression, pNone}, // Token::complement + {ExprNode::none, pExpression, pNone}, // Token::logicalNot + {ExprNode::multiply, pMultiplicative, pMultiplicative}, // Token::times + {ExprNode::divide, pMultiplicative, pMultiplicative}, // Token::divide + {ExprNode::modulo, pMultiplicative, pMultiplicative}, // Token::modulo + {ExprNode::add, pAdditive, pAdditive}, // Token::plus + {ExprNode::subtract, pAdditive, pAdditive}, // Token::minus + {ExprNode::leftShift, pShift, pShift}, // Token::leftShift + {ExprNode::rightShift, pShift, pShift}, // Token::rightShift + {ExprNode::logicalRightShift, pShift, pShift}, // Token::logicalRightShift + {ExprNode::logicalAnd, pBitwiseOr, pLogicalAnd}, // Token::logicalAnd (right-associative for efficiency) + {ExprNode::logicalXor, pLogicalAnd, pLogicalXor}, // Token::logicalXor (right-associative for efficiency) + {ExprNode::logicalOr, pLogicalXor, pLogicalOr}, // Token::logicalOr (right-associative for efficiency) + {ExprNode::bitwiseAnd, pBitwiseAnd, pBitwiseAnd}, // Token::bitwiseAnd + {ExprNode::bitwiseXor, pBitwiseXor, pBitwiseXor}, // Token::bitwiseXor + {ExprNode::bitwiseOr, pBitwiseOr, pBitwiseOr}, // Token::bitwiseOr + {ExprNode::assignment, pPostfix, pAssignment}, // Token::assignment + {ExprNode::multiplyEquals, pPostfix, pAssignment}, // Token::timesEquals + {ExprNode::divideEquals, pPostfix, pAssignment}, // Token::divideEquals + {ExprNode::moduloEquals, pPostfix, pAssignment}, // Token::moduloEquals + {ExprNode::addEquals, pPostfix, pAssignment}, // Token::plusEquals + {ExprNode::subtractEquals, pPostfix, pAssignment}, // Token::minusEquals + {ExprNode::leftShiftEquals, pPostfix, pAssignment}, // Token::leftShiftEquals + {ExprNode::rightShiftEquals, pPostfix, pAssignment}, // Token::rightShiftEquals + {ExprNode::logicalRightShiftEquals, pPostfix, pAssignment}, // Token::logicalRightShiftEquals + {ExprNode::logicalAndEquals, pPostfix, pAssignment}, // Token::logicalAndEquals + {ExprNode::logicalXorEquals, pPostfix, pAssignment}, // Token::logicalXorEquals + {ExprNode::logicalOrEquals, pPostfix, pAssignment}, // Token::logicalOrEquals + {ExprNode::bitwiseAndEquals, pPostfix, pAssignment}, // Token::bitwiseAndEquals + {ExprNode::bitwiseXorEquals, pPostfix, pAssignment}, // Token::bitwiseXorEquals + {ExprNode::bitwiseOrEquals, pPostfix, pAssignment}, // Token::bitwiseOrEquals + {ExprNode::equal, pEquality, pEquality}, // Token::equal + {ExprNode::notEqual, pEquality, pEquality}, // Token::notEqual + {ExprNode::lessThan, pRelational, pRelational}, // Token::lessThan + {ExprNode::lessThanOrEqual, pRelational, pRelational}, // Token::lessThanOrEqual + {ExprNode::greaterThan, pRelational, pRelational}, // Token::greaterThan + {ExprNode::greaterThanOrEqual, pRelational, pRelational}, // Token::greaterThanOrEqual + {ExprNode::identical, pEquality, pEquality}, // Token::identical + {ExprNode::notIdentical, pEquality, pEquality}, // Token::notIdentical + {ExprNode::conditional, pLogicalOr, pConditional}, // Token::question + + // Reserved words + {ExprNode::none, pExpression, pNone}, // Token::Abstract + {ExprNode::none, pExpression, pNone}, // Token::Break + {ExprNode::none, pExpression, pNone}, // Token::Case + {ExprNode::none, pExpression, pNone}, // Token::Catch + {ExprNode::none, pExpression, pNone}, // Token::Class + {ExprNode::none, pExpression, pNone}, // Token::Const + {ExprNode::none, pExpression, pNone}, // Token::Continue + {ExprNode::none, pExpression, pNone}, // Token::Debugger + {ExprNode::none, pExpression, pNone}, // Token::Default + {ExprNode::none, pExpression, pNone}, // Token::Delete + {ExprNode::none, pExpression, pNone}, // Token::Do + {ExprNode::none, pExpression, pNone}, // Token::Else + {ExprNode::none, pExpression, pNone}, // Token::Enum + {ExprNode::none, pExpression, pNone}, // Token::Export + {ExprNode::none, pExpression, pNone}, // Token::Extends + {ExprNode::none, pExpression, pNone}, // Token::False + {ExprNode::none, pExpression, pNone}, // Token::Final + {ExprNode::none, pExpression, pNone}, // Token::Finally + {ExprNode::none, pExpression, pNone}, // Token::For + {ExprNode::none, pExpression, pNone}, // Token::Function + {ExprNode::none, pExpression, pNone}, // Token::Goto + {ExprNode::none, pExpression, pNone}, // Token::If + {ExprNode::none, pExpression, pNone}, // Token::Implements + {ExprNode::none, pExpression, pNone}, // Token::Import + {ExprNode::In, pRelational, pRelational}, // Token::In + {ExprNode::Instanceof, pRelational, pRelational}, // Token::Instanceof + {ExprNode::none, pExpression, pNone}, // Token::Interface + {ExprNode::none, pExpression, pNone}, // Token::Namespace + {ExprNode::none, pExpression, pNone}, // Token::Native + {ExprNode::none, pExpression, pNone}, // Token::New + {ExprNode::none, pExpression, pNone}, // Token::Null + {ExprNode::none, pExpression, pNone}, // Token::Package + {ExprNode::none, pExpression, pNone}, // Token::Private + {ExprNode::none, pExpression, pNone}, // Token::Protected + {ExprNode::none, pExpression, pNone}, // Token::Public + {ExprNode::none, pExpression, pNone}, // Token::Return + {ExprNode::none, pExpression, pNone}, // Token::Static + {ExprNode::none, pExpression, pNone}, // Token::Super + {ExprNode::none, pExpression, pNone}, // Token::Switch + {ExprNode::none, pExpression, pNone}, // Token::Synchronized + {ExprNode::none, pExpression, pNone}, // Token::This + {ExprNode::none, pExpression, pNone}, // Token::Throw + {ExprNode::none, pExpression, pNone}, // Token::Throws + {ExprNode::none, pExpression, pNone}, // Token::Transient + {ExprNode::none, pExpression, pNone}, // Token::True + {ExprNode::none, pExpression, pNone}, // Token::Try + {ExprNode::none, pExpression, pNone}, // Token::Typeof + {ExprNode::none, pExpression, pNone}, // Token::Use + {ExprNode::none, pExpression, pNone}, // Token::Var + {ExprNode::none, pExpression, pNone}, // Token::Void + {ExprNode::none, pExpression, pNone}, // Token::Volatile + {ExprNode::none, pExpression, pNone}, // Token::While + {ExprNode::none, pExpression, pNone}, // Token::With + + // Non-reserved words + {ExprNode::none, pExpression, pNone}, // Token::Eval + {ExprNode::none, pExpression, pNone}, // Token::Exclude + {ExprNode::none, pExpression, pNone}, // Token::Get + {ExprNode::none, pExpression, pNone}, // Token::Include + {ExprNode::none, pExpression, pNone}, // Token::Set - case Token::Typeof: - eKind = ExprNode::Typeof; - goto getUnaryExpression; + {ExprNode::none, pExpression, pNone}, // Token::identifier - case Token::Eval: - eKind = ExprNode::Eval; - goto getUnaryExpression; + }; - case Token::plus: - eKind = ExprNode::plus; - goto getUnaryExpression; - - case Token::minus: - eKind = ExprNode::minus; - goto getUnaryExpression; - - case Token::complement: - eKind = ExprNode::complement; - goto getUnaryExpression; - - case Token::logicalNot: - eKind = ExprNode::logicalNot; - getUnaryExpression: - lexer.get(true); - checkStackSize(); - e = parseUnaryExpression(); - break; - - default: - return parsePostfixExpression(); - } - return new(arena) UnaryExprNode(pos, eKind, e); -} - - -const JS::Parser::BinaryOperatorInfo JS::Parser::tokenBinaryOperatorInfos[Token::kindsEnd] = { - // Special - {ExprNode::none, pExpression, pNone}, // Token::end - {ExprNode::none, pExpression, pNone}, // Token::number - {ExprNode::none, pExpression, pNone}, // Token::string - {ExprNode::none, pExpression, pNone}, // Token::unit - {ExprNode::none, pExpression, pNone}, // Token::regExp - - // Punctuators - {ExprNode::none, pExpression, pNone}, // Token::openParenthesis - {ExprNode::none, pExpression, pNone}, // Token::closeParenthesis - {ExprNode::none, pExpression, pNone}, // Token::openBracket - {ExprNode::none, pExpression, pNone}, // Token::closeBracket - {ExprNode::none, pExpression, pNone}, // Token::openBrace - {ExprNode::none, pExpression, pNone}, // Token::closeBrace - {ExprNode::comma, pExpression, pExpression}, // Token::comma - {ExprNode::none, pExpression, pNone}, // Token::semicolon - {ExprNode::none, pExpression, pNone}, // Token::dot - {ExprNode::none, pExpression, pNone}, // Token::doubleDot - {ExprNode::none, pExpression, pNone}, // Token::tripleDot - {ExprNode::none, pExpression, pNone}, // Token::arrow - {ExprNode::none, pExpression, pNone}, // Token::colon - {ExprNode::none, pExpression, pNone}, // Token::doubleColon - {ExprNode::none, pExpression, pNone}, // Token::pound - {ExprNode::none, pExpression, pNone}, // Token::at - {ExprNode::none, pExpression, pNone}, // Token::increment - {ExprNode::none, pExpression, pNone}, // Token::decrement - {ExprNode::none, pExpression, pNone}, // Token::complement - {ExprNode::none, pExpression, pNone}, // Token::logicalNot - {ExprNode::multiply, pMultiplicative, pMultiplicative}, // Token::times - {ExprNode::divide, pMultiplicative, pMultiplicative}, // Token::divide - {ExprNode::modulo, pMultiplicative, pMultiplicative}, // Token::modulo - {ExprNode::add, pAdditive, pAdditive}, // Token::plus - {ExprNode::subtract, pAdditive, pAdditive}, // Token::minus - {ExprNode::leftShift, pShift, pShift}, // Token::leftShift - {ExprNode::rightShift, pShift, pShift}, // Token::rightShift - {ExprNode::logicalRightShift, pShift, pShift}, // Token::logicalRightShift - {ExprNode::logicalAnd, pBitwiseOr, pLogicalAnd}, // Token::logicalAnd (right-associative for efficiency) - {ExprNode::logicalXor, pLogicalAnd, pLogicalXor}, // Token::logicalXor (right-associative for efficiency) - {ExprNode::logicalOr, pLogicalXor, pLogicalOr}, // Token::logicalOr (right-associative for efficiency) - {ExprNode::bitwiseAnd, pBitwiseAnd, pBitwiseAnd}, // Token::bitwiseAnd - {ExprNode::bitwiseXor, pBitwiseXor, pBitwiseXor}, // Token::bitwiseXor - {ExprNode::bitwiseOr, pBitwiseOr, pBitwiseOr}, // Token::bitwiseOr - {ExprNode::assignment, pPostfix, pAssignment}, // Token::assignment - {ExprNode::multiplyEquals, pPostfix, pAssignment}, // Token::timesEquals - {ExprNode::divideEquals, pPostfix, pAssignment}, // Token::divideEquals - {ExprNode::moduloEquals, pPostfix, pAssignment}, // Token::moduloEquals - {ExprNode::addEquals, pPostfix, pAssignment}, // Token::plusEquals - {ExprNode::subtractEquals, pPostfix, pAssignment}, // Token::minusEquals - {ExprNode::leftShiftEquals, pPostfix, pAssignment}, // Token::leftShiftEquals - {ExprNode::rightShiftEquals, pPostfix, pAssignment}, // Token::rightShiftEquals - {ExprNode::logicalRightShiftEquals, pPostfix, pAssignment}, // Token::logicalRightShiftEquals - {ExprNode::logicalAndEquals, pPostfix, pAssignment}, // Token::logicalAndEquals - {ExprNode::logicalXorEquals, pPostfix, pAssignment}, // Token::logicalXorEquals - {ExprNode::logicalOrEquals, pPostfix, pAssignment}, // Token::logicalOrEquals - {ExprNode::bitwiseAndEquals, pPostfix, pAssignment}, // Token::bitwiseAndEquals - {ExprNode::bitwiseXorEquals, pPostfix, pAssignment}, // Token::bitwiseXorEquals - {ExprNode::bitwiseOrEquals, pPostfix, pAssignment}, // Token::bitwiseOrEquals - {ExprNode::equal, pEquality, pEquality}, // Token::equal - {ExprNode::notEqual, pEquality, pEquality}, // Token::notEqual - {ExprNode::lessThan, pRelational, pRelational}, // Token::lessThan - {ExprNode::lessThanOrEqual, pRelational, pRelational}, // Token::lessThanOrEqual - {ExprNode::greaterThan, pRelational, pRelational}, // Token::greaterThan - {ExprNode::greaterThanOrEqual, pRelational, pRelational}, // Token::greaterThanOrEqual - {ExprNode::identical, pEquality, pEquality}, // Token::identical - {ExprNode::notIdentical, pEquality, pEquality}, // Token::notIdentical - {ExprNode::conditional, pLogicalOr, pConditional}, // Token::question - - // Reserved words - {ExprNode::none, pExpression, pNone}, // Token::Abstract - {ExprNode::none, pExpression, pNone}, // Token::Break - {ExprNode::none, pExpression, pNone}, // Token::Case - {ExprNode::none, pExpression, pNone}, // Token::Catch - {ExprNode::none, pExpression, pNone}, // Token::Class - {ExprNode::none, pExpression, pNone}, // Token::Const - {ExprNode::none, pExpression, pNone}, // Token::Continue - {ExprNode::none, pExpression, pNone}, // Token::Debugger - {ExprNode::none, pExpression, pNone}, // Token::Default - {ExprNode::none, pExpression, pNone}, // Token::Delete - {ExprNode::none, pExpression, pNone}, // Token::Do - {ExprNode::none, pExpression, pNone}, // Token::Else - {ExprNode::none, pExpression, pNone}, // Token::Enum - {ExprNode::none, pExpression, pNone}, // Token::Eval - {ExprNode::none, pExpression, pNone}, // Token::Export - {ExprNode::none, pExpression, pNone}, // Token::Extends - {ExprNode::none, pExpression, pNone}, // Token::False - {ExprNode::none, pExpression, pNone}, // Token::Final - {ExprNode::none, pExpression, pNone}, // Token::Finally - {ExprNode::none, pExpression, pNone}, // Token::For - {ExprNode::none, pExpression, pNone}, // Token::Function - {ExprNode::none, pExpression, pNone}, // Token::Goto - {ExprNode::none, pExpression, pNone}, // Token::If - {ExprNode::none, pExpression, pNone}, // Token::Implements - {ExprNode::none, pExpression, pNone}, // Token::Import - {ExprNode::In, pRelational, pRelational}, // Token::In - {ExprNode::Instanceof, pRelational, pRelational}, // Token::Instanceof - {ExprNode::none, pExpression, pNone}, // Token::Interface - {ExprNode::none, pExpression, pNone}, // Token::Native - {ExprNode::none, pExpression, pNone}, // Token::New - {ExprNode::none, pExpression, pNone}, // Token::Null - {ExprNode::none, pExpression, pNone}, // Token::Package - {ExprNode::none, pExpression, pNone}, // Token::Private - {ExprNode::none, pExpression, pNone}, // Token::Protected - {ExprNode::none, pExpression, pNone}, // Token::Public - {ExprNode::none, pExpression, pNone}, // Token::Return - {ExprNode::none, pExpression, pNone}, // Token::Static - {ExprNode::none, pExpression, pNone}, // Token::Super - {ExprNode::none, pExpression, pNone}, // Token::Switch - {ExprNode::none, pExpression, pNone}, // Token::Synchronized - {ExprNode::none, pExpression, pNone}, // Token::This - {ExprNode::none, pExpression, pNone}, // Token::Throw - {ExprNode::none, pExpression, pNone}, // Token::Throws - {ExprNode::none, pExpression, pNone}, // Token::Transient - {ExprNode::none, pExpression, pNone}, // Token::True - {ExprNode::none, pExpression, pNone}, // Token::Try - {ExprNode::none, pExpression, pNone}, // Token::Typeof - {ExprNode::none, pExpression, pNone}, // Token::Var - {ExprNode::none, pExpression, pNone}, // Token::Volatile - {ExprNode::none, pExpression, pNone}, // Token::While - {ExprNode::none, pExpression, pNone}, // Token::With - - // Non-reserved words - {ExprNode::none, pExpression, pNone}, // Token::Attribute - {ExprNode::none, pExpression, pNone}, // Token::Constructor - {ExprNode::none, pExpression, pNone}, // Token::Get - {ExprNode::none, pExpression, pNone}, // Token::Language - {ExprNode::none, pExpression, pNone}, // Token::Namespace - {ExprNode::none, pExpression, pNone}, // Token::Set - {ExprNode::none, pExpression, pNone}, // Token::Use - - {ExprNode::none, pExpression, pNone} // Token::identifier + struct Parser::StackedSubexpression { + ExprNode::Kind kind; // The kind of BinaryExprNode the subexpression + // should generate + uchar precedence; // Precedence of an operator with respect to + // operators on its right + uint32 pos; // The operator token's position + ExprNode *op1; // First operand of the operator + ExprNode *op2; // Second operand of the operator (used for ?: + // only) }; +// Parse and return an Expression. If noIn is false, allow the in operator. +// If noAssignment is false, allow the = and op= operators. If noComma is +// false, allow the comma operator. If the first token was peeked, it should +// be have been done with preferRegExp set to true. +// After parseExpression finishes, the next token might have been peeked with +// preferRegExp set to false. + ExprNode * + Parser::parseExpression(bool noIn, bool noAssignment, bool noComma) + { + ArrayBuffer subexpressionStack; -struct JS::Parser::StackedSubexpression { - ExprNode::Kind kind; // The kind of BinaryExprNode the subexpression should generate - uchar precedence; // Precedence of an operator with respect to operators on its right - uint32 pos; // The operator token's position - ExprNode *op1; // First operand of the operator - ExprNode *op2; // Second operand of the operator (used for ?: only) -}; - - -// Parse and return an Expression. If noIn is false, allow the in operator. If noAssignment is -// false, allow the = and op= operators. If noComma is false, allow the comma operator. -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseExpression finishes, the next token might have been peeked with preferRegExp set to false. -JS::ExprNode *JS::Parser::parseExpression(bool noIn, bool noAssignment, bool noComma) -{ - ArrayBuffer subexpressionStack; - - checkStackSize(); - // Push a limiter onto subexpressionStack. - subexpressionStack.reserve_advance_back()->precedence = pNone; - - while (true) { - foundColon: - ExprNode *e = parseUnaryExpression(); - - const Token &t = lexer.peek(false); - const BinaryOperatorInfo &binOpInfo = tokenBinaryOperatorInfos[t.getKind()]; - Precedence precedence = binOpInfo.precedenceLeft; - ExprNode::Kind kind = binOpInfo.kind; - ASSERT(precedence > pNone); - - // Disqualify assignments, 'in', and comma if the flags indicate that these should end the expression. - if (precedence == pPostfix && noAssignment || kind == ExprNode::In && noIn || kind == ExprNode::comma && noComma) { - kind = ExprNode::none; - precedence = pExpression; - } - - if (precedence == pPostfix) - ensurePostfix(e); // Ensure that the target of an assignment is a postfix subexpression. - else - // Reduce already stacked operators with precedenceLeft or higher precedence - while (subexpressionStack.back().precedence >= precedence) { - StackedSubexpression &s = subexpressionStack.pop_back(); - if (s.kind == ExprNode::conditional) { - if (s.op2) - e = new(arena) TernaryExprNode(s.pos, s.kind, s.op1, s.op2, e); - else { - if (!t.hasKind(Token::colon)) - syntaxError("':' expected", 0); - lexer.get(false); - subexpressionStack.advance_back(); - s.op2 = e; - goto foundColon; - } - } else - e = new(arena) BinaryExprNode(s.pos, s.kind, s.op1, e); - } - - if (kind == ExprNode::none) { - ASSERT(subexpressionStack.size() == 1); - return e; - } - - // Push the current operator onto the subexpressionStack. - lexer.get(false); - StackedSubexpression &s = *subexpressionStack.reserve_advance_back(); - s.kind = kind; - s.precedence = binOpInfo.precedenceRight; - s.pos = t.getPos(); - s.op1 = e; - s.op2 = 0; - } -} - - -// Parse an opening parenthesis, an Expression, and a closing parenthesis. Return the Expression. -// If the first token was peeked, it should be have been done with preferRegExp set to true. -JS::ExprNode *JS::Parser::parseParenthesizedExpression() -{ - require(true, Token::openParenthesis); - ExprNode *e = parseExpression(false); - require(false, Token::closeParenthesis); - return e; -} + checkStackSize(); + // Push a limiter onto subexpressionStack. + subexpressionStack.reserve_advance_back()->precedence = pNone; + while (true) { + foundColon: + ExprNode *e = parseUnaryExpression(); + + const Token &t = lexer.peek(false); + const BinaryOperatorInfo &binOpInfo = + tokenBinaryOperatorInfos[t.getKind()]; + Precedence precedence = binOpInfo.precedenceLeft; + ExprNode::Kind kind = binOpInfo.kind; + ASSERT(precedence > pNone); + + // Disqualify assignments, 'in', and comma if the flags + // indicate that these should end the expression. + if (precedence == pPostfix && noAssignment || + kind == ExprNode::In && noIn || + kind == ExprNode::comma && noComma) { + kind = ExprNode::none; + precedence = pExpression; + } + + if (precedence == pPostfix) + ensurePostfix(e); // Ensure that the target of an assignment + // is a postfix subexpression. + else + // Reduce already stacked operators with precedenceLeft or + // higher precedence + while (subexpressionStack.back().precedence >= precedence) { + StackedSubexpression &s = subexpressionStack.pop_back(); + if (s.kind == ExprNode::conditional) { + if (s.op2) + e = new(arena) TernaryExprNode(s.pos, s.kind, + s.op1, s.op2, e); + else { + if (!t.hasKind(Token::colon)) + syntaxError("':' expected", 0); + lexer.get(false); + subexpressionStack.advance_back(); + s.op2 = e; + goto foundColon; + } + } else + e = new(arena) BinaryExprNode(s.pos, s.kind, s.op1, e); + } + + if (kind == ExprNode::none) { + ASSERT(subexpressionStack.size() == 1); + return e; + } + + // Push the current operator onto the subexpressionStack. + lexer.get(false); + StackedSubexpression &s = + *subexpressionStack.reserve_advance_back(); + s.kind = kind; + s.precedence = binOpInfo.precedenceRight; + s.pos = t.getPos(); + s.op1 = e; + s.op2 = 0; + } + } +// Parse an opening parenthesis, an Expression, and a closing parenthesis. +// Return the Expression. If the first token was peeked, it should be have +// been done with preferRegExp set to true. + ExprNode * + Parser::parseParenthesizedExpression() + { + require(true, Token::openParenthesis); + ExprNode *e = parseExpression(false); + require(false, Token::closeParenthesis); + return e; + } + + // Parse and return a TypeExpression. If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseTypeExpression finishes, the next token might have been peeked with preferRegExp set to true. -JS::ExprNode *JS::Parser::parseTypeExpression(bool noIn) -{ - ExprNode *type = parseNonAssignmentExpression(noIn); - if (lexer.peek(false).hasKind(Token::divideEquals)) - syntaxError("'/=' not allowed here", 0); - lexer.redesignate(true); // Safe: a '/' would have been interpreted as an operator, so it can't be the next token; - // a '/=' was outlawed by the check above. - return type; -} +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. After parseTypeExpression finishes, the next +// token might have been peeked with preferRegExp set to true. + ExprNode * + Parser::parseTypeExpression(bool noIn) + { + ExprNode *type = parseNonAssignmentExpression(noIn); + if (lexer.peek(false).hasKind(Token::divideEquals)) + syntaxError("'/=' not allowed here", 0); + lexer.redesignate(true); // Safe: a '/' would have been interpreted + // as an operator, so it can't be the next + // token; + // a '/=' was outlawed by the check above. + return type; + } // Parse a TypedIdentifier. Return the identifier's name. // If a type was provided, set type to it; otherwise, set type to nil. -// After parseTypedIdentifier finishes, the next token might have been peeked with preferRegExp set to false. -const JS::StringAtom &JS::Parser::parseTypedIdentifier(ExprNode *&type) -{ - const Token &t = lexer.get(true); - if (!t.hasIdentifierKind()) - syntaxError("Identifier expected"); - const StringAtom &name = t.getIdentifier(); +// After parseTypedIdentifier finishes, the next token might have been peeked +// with preferRegExp set to false. + const StringAtom & + Parser::parseTypedIdentifier(ExprNode *&type) + { + const Token &t = lexer.get(true); + if (!t.hasIdentifierKind()) + syntaxError("Identifier expected"); + const StringAtom &name = t.getIdentifier(); - type = 0; - if (lexer.eat(false, Token::colon)) - type = parseNonAssignmentExpression(false); - return name; -} + type = 0; + if (lexer.eat(false, Token::colon)) + type = parseNonAssignmentExpression(false); + return name; + } - -// If the next token has the given kind, eat it and parse and return the following TypeExpression; -// otherwise return nil. +// If the next token has the given kind, eat it and parse and return the +// following TypeExpression; otherwise return nil. // If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseTypeBinding finishes, the next token might have been peeked with preferRegExp set to true. -JS::ExprNode *JS::Parser::parseTypeBinding(Token::Kind kind, bool noIn) -{ - ExprNode *type = 0; - if (lexer.eat(true, kind)) - type = parseTypeExpression(noIn); - return type; -} +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseTypeBinding finishes, the next token might have been peeked +// with preferRegExp set to true. + ExprNode * + Parser::parseTypeBinding(Token::Kind kind, bool noIn) + { + ExprNode *type = 0; + if (lexer.eat(true, kind)) + type = parseTypeExpression(noIn); + return type; + } - -// If the next token has the given kind, eat it and parse and return the following TypeExpressionList; -// otherwise return nil. +// If the next token has the given kind, eat it and parse and return the +// following TypeExpressionList; otherwise return nil. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseTypeListBinding finishes, the next token might have been peeked with preferRegExp set to true. -JS::ExprList *JS::Parser::parseTypeListBinding(Token::Kind kind) -{ - NodeQueue types; - if (lexer.eat(true, kind)) - do types += new(arena) ExprList(parseTypeExpression(false)); - while (lexer.eat(true, Token::comma)); - return types.first; -} - +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseTypeListBinding finishes, the next token might have been peeked +// with preferRegExp set to true. + ExprList * + Parser::parseTypeListBinding(Token::Kind kind) + { + NodeQueue types; + if (lexer.eat(true, kind)) + do types += new(arena) ExprList(parseTypeExpression(false)); + while (lexer.eat(true, Token::comma)); + return types.first; + } // Parse and return a VariableBinding. -// If noQualifiers is false, allow a QualifiedIdentifier as the variable name; otherwise, restrict the -// variable name to be a simple Identifier. +// If noQualifiers is false, allow a QualifiedIdentifier as the variable name; +// otherwise, restrict the variable name to be a simple Identifier. // If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseVariableBinding finishes, the next token might have been peeked with preferRegExp set to true. -JS::VariableBinding *JS::Parser::parseVariableBinding(bool noQualifiers, bool noIn) -{ - const Token &t = lexer.get(true); - uint32 pos = t.getPos(); - - ExprNode *name; - if (noQualifiers) { - name = makeIdentifierExpression(t); - if (!name) - syntaxError("Identifier expected"); - } else - name = parseQualifiedIdentifier(t, true); - - ExprNode *type = parseTypeBinding(Token::colon, noIn); - - ExprNode *initializer = 0; - if (lexer.eat(true, Token::assignment)) { - initializer = parseAssignmentExpression(noIn); - lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token. - } - - return new(arena) VariableBinding(pos, name, type, initializer); -} +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseVariableBinding finishes, the next token might have been peeked +// with preferRegExp set to true. + VariableBinding * + Parser::parseVariableBinding(bool noQualifiers, bool noIn, bool constant) + { + const Token &t = lexer.get(true); + uint32 pos = t.getPos(); + ExprNode *name; + if (noQualifiers) { + name = makeIdentifierExpression(t); + if (!name) + syntaxError("Identifier expected"); + } else + name = parseQualifiedIdentifier(t, true); + + ExprNode *type = parseTypeBinding(Token::colon, noIn); + + ExprNode *initializer = 0; + if (lexer.eat(true, Token::assignment)) { + initializer = parseAssignmentExpression(noIn); + lexer.redesignate(true); // Safe: a '/' or a '/=' would have + // been interpreted as an operator, so + // it can't be the next token. + } + + return new(arena) VariableBinding(pos, name, type, initializer, + constant); + } // Parse a FunctionName and initialize fn with the result. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseFunctionName finishes, the next token might have been peeked with preferRegExp set to true. -void JS::Parser::parseFunctionName(FunctionName &fn) -{ - fn.prefix = FunctionName::normal; - const Token *t = &lexer.get(true); - if (t->hasKind(Token::Get) || t->hasKind(Token::Set)) { - const Token *t2 = &lexer.peek(true); - if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowGet)) { - fn.prefix = t->hasKind(Token::Get) ? FunctionName::Get : FunctionName::Set; - t = &lexer.get(true); - } - } - - fn.name = parseQualifiedIdentifier(*t, true); -} +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseFunctionName finishes, the next token might have been peeked +// with preferRegExp set to true. + void + Parser::parseFunctionName(FunctionName &fn) + { + fn.prefix = FunctionName::normal; + const Token *t = &lexer.get(true); + if (t->hasKind(Token::Get) || t->hasKind(Token::Set)) { + const Token *t2 = &lexer.peek(true); + if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowGet)) { + fn.prefix = t->hasKind(Token::Get) ? FunctionName::Get : + FunctionName::Set; + t = &lexer.get(true); + } + } + + fn.name = parseQualifiedIdentifier(*t, true); + } // Parse a FunctionSignature and initialize fd with the result. // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseFunctionSignature finishes, the next token might have been peeked with preferRegExp set to true. -void JS::Parser::parseFunctionSignature(FunctionDefinition &fd) -{ - require(true, Token::openParenthesis); - - NodeQueue parameters; - VariableBinding *optParameters = 0; - VariableBinding *namedParameters = 0; - VariableBinding *restParameter = 0; +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseFunctionSignature finishes, the next token might have been +// peeked with preferRegExp set to true. + void + Parser::parseFunctionSignature(FunctionDefinition &fd) + { + require(true, Token::openParenthesis); + + NodeQueue parameters; + VariableBinding *optParameters = 0; + VariableBinding *namedParameters = 0; + VariableBinding *restParameter = 0; #ifdef NEW_PARSER - fd.optParameters = optParameters; - fd.namedParameters = namedParameters; - fd.restParameter = restParameter; + fd.optParameters = optParameters; + fd.namedParameters = namedParameters; + fd.restParameter = restParameter; #endif - if (!lexer.eat(true, Token::closeParenthesis)) { + if (!lexer.eat(true, Token::closeParenthesis)) { #ifdef NEW_PARSER - parseAllParameters(fd,parameters); - match(Token::closeParenthesis); + parseAllParameters(fd,parameters); + match(Token::closeParenthesis); #else - while (true) { - if (lexer.eat(true, Token::tripleDot)) { - const Token &t1 = lexer.peek(true); - if (t1.hasKind(Token::closeParenthesis)) - restParameter = new(arena) VariableBinding(t1.getPos(), 0, 0, 0); - else - restParameter = parseVariableBinding(true, false); - if (!optParameters) - optParameters = restParameter; - parameters += restParameter; - require(true, Token::closeParenthesis); - break; - } else { - VariableBinding *b = parseVariableBinding(true, false); - if (b->initializer) { - if (!optParameters) - optParameters = b; - } else - if (optParameters) - syntaxError("'=' expected", 0); - parameters += b; - const Token &t = lexer.get(true); - if (!t.hasKind(Token::comma)) - if (t.hasKind(Token::closeParenthesis)) - break; - else - syntaxError("',' or ')' expected"); - } - } -#endif - } - fd.parameters = parameters.first; -#ifndef NEW_PARSER - fd.optParameters = optParameters; - fd.restParameter = restParameter; - fd.resultType = parseTypeBinding(Token::colon, false); -#endif - fd.resultType = parseResultSignature(); -} - -// Parse a list of statements ending with a '}'. Return these statements as a linked list -// threaded through the StmtNodes' next fields. The opening '{' has already been read. -// If noCloseBrace is true, an end-of-input terminates the block; the end-of-input token is not read. -// If inSwitch is true, allow case : and default: statements. -// If noCloseBrace is true, after parseBlock finishes the next token might have been peeked with preferRegExp set to true. -JS::StmtNode *JS::Parser::parseBlock(bool inSwitch, bool noCloseBrace) -{ - NodeQueue q; - SemicolonState semicolonState = semiNone; - - while (true) { - const Token *t = &lexer.peek(true); - if (t->hasKind(Token::semicolon) && semicolonState != semiNone) { - lexer.get(true); - semicolonState = semiNone; - t = &lexer.peek(true); - } - if (noCloseBrace) { - if (t->hasKind(Token::end)) - return q.first; - } else if (t->hasKind(Token::closeBrace)) { - lexer.get(true); - return q.first; - } - if (!(semicolonState == semiNone || semicolonState == semiInsertable && lineBreakBefore(*t))) - syntaxError("';' expected", 0); - - StmtNode *s = parseStatement(!inSwitch, inSwitch, semicolonState); - if (inSwitch && !q.first && !s->hasKind(StmtNode::Case)) - syntaxError("First statement in a switch block must be 'case expr:' or 'default:'", 0); - q += s; - } -} - - -// Parse an optional block of statements beginning with a '{' and ending with a '}'. -// Return these statements as a BlockStmtNode. -// If semicolonState is nil, the block is required; otherwise, the block is optional and if it is -// omitted, *semicolonState is set to semiInsertable. -// -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseBody finishes, the next token might have been peeked with preferRegExp set to true. -JS::BlockStmtNode *JS::Parser::parseBody(SemicolonState *semicolonState) -{ - const Token *tBrace = lexer.eat(true, Token::openBrace); - if (tBrace) { - uint32 pos = tBrace->getPos(); - return new(arena) BlockStmtNode(pos, StmtNode::block, 0, parseBlock(false, false)); - } else { - if (!semicolonState) - syntaxError("'{' expected", 0); - *semicolonState = semiInsertable; - return 0; - } -} - -JS::ExprNode::Kind JS::Parser::validateOperatorName(const Token &name) -{ - Lexer operatorLexer(getWorld(), copyTokenChars(name), getReader().sourceLocation); // XXX line number ??? - - const Token &t = operatorLexer.get(false); // XXX preferRegExp ??? - - // XXX switch to a table lookup instead - switch (t.getKind()) { - default: - syntaxError("Illegal operator name"); - - case Token::complement: - return ExprNode::complement; - case Token::increment: - return ExprNode::postIncrement; - case Token::decrement: - return ExprNode::postDecrement; - case Token::Const: - return ExprNode::none; // XXX - - case Token::plus: - return ExprNode::add; - case Token::minus: - return ExprNode::subtract; - case Token::times: - return ExprNode::multiply; - case Token::divide: - return ExprNode::divide; - case Token::modulo: - return ExprNode::modulo; - case Token::leftShift: - return ExprNode::leftShift; - case Token::rightShift: - return ExprNode::rightShift; - case Token::logicalRightShift: - return ExprNode::logicalRightShift; - case Token::lessThan: - return ExprNode::lessThan; - case Token::lessThanOrEqual: - return ExprNode::lessThanOrEqual; - case Token::equal: - return ExprNode::equal; - case Token::bitwiseAnd: - return ExprNode::bitwiseAnd; - case Token::bitwiseXor: - return ExprNode::bitwiseXor; - case Token::bitwiseOr: - return ExprNode::bitwiseOr; - case Token::identical: - return ExprNode::identical; - case Token::In: - return ExprNode::In; - - case Token::openParenthesis: - return ExprNode::call; - - case Token::New: - return ExprNode::New; - - case Token::openBracket: - return ExprNode::index; - - case Token::Delete: - return ExprNode::Delete; - } - - return ExprNode::none; - -} - -// Parse and return a statement that takes zero or more initial attributes, which have already been parsed. -// If noIn is false, allow the in operator. -// -// If the statement ends with an optional semicolon, that semicolon is not parsed. -// Instead, parseAttributeStatement returns in semicolonState one of three values: -// semiNone: No semicolon is needed to close the statement -// semiNoninsertable: A NoninsertableSemicolon is needed to close the statement; a line break is not enough -// semiInsertable: A Semicolon is needed to close the statement; a line break is also sufficient -// -// pos is the position of the beginning of the statement (its first attribute if it has attributes). -// The first token of the statement has already been read and is provided in t. -// After parseAttributeStatement finishes, the next token might have been peeked with preferRegExp set to true. -JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, - bool noIn, SemicolonState &semicolonState) -{ - semicolonState = semiNone; - StmtNode::Kind sKind; - - switch (t.getKind()) { - case Token::openBrace: - return new(arena) BlockStmtNode(pos, StmtNode::block, attributes, parseBlock(false, false)); - - case Token::Const: - sKind = StmtNode::Const; - goto constOrVar; - case Token::Var: - sKind = StmtNode::Var; - constOrVar: - { - NodeQueue bindings; - - do bindings += parseVariableBinding(false, noIn); - while (lexer.eat(true, Token::comma)); - semicolonState = semiInsertable; - return new(arena) VariableStmtNode(pos, sKind, attributes, bindings.first); - } - - case Token::Constructor: - sKind = StmtNode::Constructor; - goto functionOrConstructor; - case Token::Function: - sKind = StmtNode::Function; - functionOrConstructor: - { - FunctionStmtNode *f = new(arena) FunctionStmtNode(pos, sKind, attributes); - if (sKind == StmtNode::Constructor) { - f->function.prefix = FunctionName::normal; - const Token &t2 = lexer.get(false); - if (lineBreakBefore(t2) || !(f->function.name = makeIdentifierExpression(t2))) - syntaxError("Constructor name expected"); - } else - if (attributes && attributes->contains(Token::Operator)) { - // expecting a string literal matching one of the legal operator names - const Token &t2 = lexer.get(false); - if (!t2.hasKind(Token::string)) - syntaxError("Operator name (as string literal) expected"); - f->function.prefix = FunctionName::Operator; - f->function.op = validateOperatorName(t2); - f->function.name = NULL; + while (true) { + if (lexer.eat(true, Token::tripleDot)) { + const Token &t1 = lexer.peek(true); + if (t1.hasKind(Token::closeParenthesis)) + restParameter = new(arena) VariableBinding(t1.getPos(), + 0, 0, 0, + false); + else + restParameter = parseVariableBinding(true, false, + lexer.eat(true, + Token::Const)); + if (!optParameters) + optParameters = restParameter; + parameters += restParameter; + require(true, Token::closeParenthesis); + break; + } else { + VariableBinding *b = parseVariableBinding(true, false, + lexer.eat(true, + Token::Const)); + if (b->initializer) { + if (!optParameters) + optParameters = b; + } else + if (optParameters) + syntaxError("'=' expected", 0); + parameters += b; + const Token &t = lexer.get(true); + if (!t.hasKind(Token::comma)) + if (t.hasKind(Token::closeParenthesis)) + break; + else + syntaxError("',' or ')' expected"); } - else - parseFunctionName(f->function); - parseFunctionSignature(f->function); - f->function.body = parseBody(&semicolonState); - return f; - } + } +#endif + } + fd.parameters = parameters.first; +#ifndef NEW_PARSER + fd.optParameters = optParameters; + fd.restParameter = restParameter; + fd.resultType = parseTypeBinding(Token::colon, false); +#endif + fd.resultType = parseResultSignature(); + } + +// Parse a list of statements ending with a '}'. Return these statements as a +// linked list threaded through the StmtNodes' next fields. The opening '{' +// has already been read. If noCloseBrace is true, an end-of-input terminates +// the block; the end-of-input token is not read. +// If inSwitch is true, allow case : and default: statements. +// If noCloseBrace is true, after parseBlock finishes the next token might +// have been peeked with preferRegExp set to true. + StmtNode * + Parser::parseBlock(bool inSwitch, bool noCloseBrace) + { + NodeQueue q; + SemicolonState semicolonState = semiNone; + + while (true) { + const Token *t = &lexer.peek(true); + if (t->hasKind(Token::semicolon) && semicolonState != semiNone) { + lexer.get(true); + semicolonState = semiNone; + t = &lexer.peek(true); + } + if (noCloseBrace) { + if (t->hasKind(Token::end)) + return q.first; + } else if (t->hasKind(Token::closeBrace)) { + lexer.get(true); + return q.first; + } + if (!(semicolonState == semiNone || + semicolonState == semiInsertable && lineBreakBefore(*t))) + syntaxError("';' expected", 0); + + StmtNode *s = parseStatement(!inSwitch, inSwitch, semicolonState); + if (inSwitch && !q.first && !s->hasKind(StmtNode::Case)) + syntaxError("First statement in a switch block must be " + "'case expr:' or 'default:'", 0); + q += s; + } + } + + +// Parse an optional block of statements beginning with a '{' and ending +// with a '}'. Return these statements as a BlockStmtNode. +// If semicolonState is nil, the block is required; otherwise, the block is +// optional and if it is omitted, *semicolonState is set to semiInsertable. +// +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. After parseBody finishes, the next token might +// have been peeked with preferRegExp set to true. + BlockStmtNode * + Parser::parseBody(SemicolonState *semicolonState) + { + const Token *tBrace = lexer.eat(true, Token::openBrace); + if (tBrace) { + uint32 pos = tBrace->getPos(); + return new(arena) BlockStmtNode(pos, StmtNode::block, 0, + parseBlock(false, false)); + } else { + if (!semicolonState) + syntaxError("'{' expected", 0); + *semicolonState = semiInsertable; + return 0; + } + } + + ExprNode::Kind + Parser::validateOperatorName(const Token &name) + { + Lexer operatorLexer(getWorld(), copyTokenChars(name), + getReader().sourceLocation); // XXX line number ??? + + const Token &t = operatorLexer.get(false); // XXX preferRegExp ??? - case Token::Interface: - sKind = StmtNode::Interface; - goto classOrInterface; - case Token::Class: - sKind = StmtNode::Class; - classOrInterface: - { - ExprNode *name = parseQualifiedIdentifier(lexer.get(true), true); - ExprNode *superclass = 0; - if (sKind == StmtNode::Class) - superclass = parseTypeBinding(Token::Extends, false); - ExprList *superinterfaces = parseTypeListBinding(sKind == StmtNode::Class ? Token::Implements : Token::Extends); - BlockStmtNode *body = parseBody(superclass || superinterfaces ? 0 : &semicolonState); - return new(arena) ClassStmtNode(pos, sKind, attributes, name, superclass, superinterfaces, body); - } + // XXX switch to a table lookup instead + switch (t.getKind()) { + default: + syntaxError("Illegal operator name"); - case Token::Namespace: - { - const Token &t2 = lexer.get(false); - ExprNode *name; - if (lineBreakBefore(t2) || !(name = makeIdentifierExpression(t2))) - syntaxError("Namespace name expected"); - ExprList *supernamespaces = parseTypeListBinding(Token::Extends); - semicolonState = semiInsertable; - return new(arena) NamespaceStmtNode(pos, StmtNode::Namespace, attributes, name, supernamespaces); - } - - default: - syntaxError("Bad declaration"); - return 0; - } -} + case Token::complement: + return ExprNode::complement; + case Token::increment: + return ExprNode::postIncrement; + case Token::decrement: + return ExprNode::postDecrement; + case Token::Const: + return ExprNode::none; // XXX + + case Token::plus: + return ExprNode::add; + case Token::minus: + return ExprNode::subtract; + case Token::times: + return ExprNode::multiply; + case Token::divide: + return ExprNode::divide; + case Token::modulo: + return ExprNode::modulo; + case Token::leftShift: + return ExprNode::leftShift; + case Token::rightShift: + return ExprNode::rightShift; + case Token::logicalRightShift: + return ExprNode::logicalRightShift; + case Token::lessThan: + return ExprNode::lessThan; + case Token::lessThanOrEqual: + return ExprNode::lessThanOrEqual; + case Token::equal: + return ExprNode::equal; + case Token::bitwiseAnd: + return ExprNode::bitwiseAnd; + case Token::bitwiseXor: + return ExprNode::bitwiseXor; + case Token::bitwiseOr: + return ExprNode::bitwiseOr; + case Token::identical: + return ExprNode::identical; + case Token::In: + return ExprNode::In; + + case Token::openParenthesis: + return ExprNode::call; + + case Token::New: + return ExprNode::New; + + case Token::openBracket: + return ExprNode::index; + + case Token::Delete: + return ExprNode::Delete; + } + + return ExprNode::none; + + } + +// Parse and return a statement that takes zero or more initial attributes, +// which have already been parsed. If noIn is false, allow the in operator. +// +// If the statement ends with an optional semicolon, that semicolon is not +// parsed. Instead, parseAttributeStatement returns in semicolonState one of +// three values: +// semiNone: No semicolon is needed to close the statement +// semiNoninsertable: A NoninsertableSemicolon is needed to close the +// statement; a line break is not enough +// semiInsertable: A Semicolon is needed to close the statement; a +// line break is also sufficient +// +// pos is the position of the beginning of the statement (its first attribute +// if it has attributes). The first token of the statement has already been +// read and is provided in t. After parseAttributeStatement finishes, the next +// token might have been peeked with preferRegExp set to true. + StmtNode * + Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, + const Token &t, bool noIn, + SemicolonState &semicolonState) + { + semicolonState = semiNone; + StmtNode::Kind sKind; + + switch (t.getKind()) { + case Token::openBrace: + return new(arena) BlockStmtNode(pos, StmtNode::block, + attributes, + parseBlock(false, false)); + + case Token::Const: + sKind = StmtNode::Const; + goto constOrVar; + case Token::Var: + sKind = StmtNode::Var; + constOrVar: + { + NodeQueue bindings; + + do bindings += parseVariableBinding(false, noIn, + sKind == StmtNode::Const); + while (lexer.eat(true, Token::comma)); + semicolonState = semiInsertable; + return new(arena) VariableStmtNode(pos, sKind, + attributes, + bindings.first); + } + + case Token::Function: + sKind = StmtNode::Function; + { + FunctionStmtNode *f = + new(arena) FunctionStmtNode(pos, sKind, attributes); +/* + if (attributes && + attributes->contains(Token::Operator)) { + // expecting a string literal matching one + // of the legal operator names + const Token &t2 = lexer.get(false); + if (!t2.hasKind(Token::string)) + syntaxError("Operator name (as string " + "literal) expected"); + f->function.prefix = FunctionName::Operator; + f->function.op = validateOperatorName(t2); + f->function.name = NULL; + } + else +*/ + parseFunctionName(f->function); + parseFunctionSignature(f->function); + f->function.body = parseBody(&semicolonState); + return f; + } + + case Token::Interface: + sKind = StmtNode::Interface; + goto classOrInterface; + case Token::Class: + sKind = StmtNode::Class; + classOrInterface: + { + ExprNode *name = parseQualifiedIdentifier(lexer.get(true), + true); + ExprNode *superclass = 0; + if (sKind == StmtNode::Class) + superclass = parseTypeBinding(Token::Extends, false); + ExprList *superinterfaces = + parseTypeListBinding(sKind == StmtNode::Class ? + Token::Implements : + Token::Extends); + BlockStmtNode *body = + parseBody(superclass || superinterfaces ? + 0 : &semicolonState); + return new(arena) ClassStmtNode(pos, sKind, attributes, + name, superclass, + superinterfaces, body); + } + case Token::Namespace: + { + const Token &t2 = lexer.get(false); + ExprNode *name; + if (lineBreakBefore(t2) || + !(name = makeIdentifierExpression(t2))) + syntaxError("Namespace name expected"); + ExprList *supernamespaces = + parseTypeListBinding(Token::Extends); + semicolonState = semiInsertable; + return new(arena) NamespaceStmtNode(pos, StmtNode::Namespace, + attributes, name, + supernamespaces); + } + default: + syntaxError("Bad declaration"); + return 0; + } + } + + // Parse and return a statement that takes zero or more initial attributes. // semicolonState behaves as in parseAttributeStatement. // // as restricts the kinds of statements that are allowed after the attributes: -// asAny Any statements that takes attributes can follow -// asBlock Only a block can follow -// asConstVar Only a const or var declaration can follow, and the 'in' operator is not allowed at its top level +// asAny Any statements that takes attributes can follow +// asBlock Only a block can follow +// asConstVar Only a const or var declaration can follow, and the 'in' +// operator is not allowed at its top level // // The first token of the statement has already been read and is provided in t. -// If the second token was peeked, it should be have been done with preferRegExp set to false; -// the second token should have been peeked only if t is an attribute or the keyword 'constructor'. -// After parseAttributesAndStatement finishes, the next token might have been peeked with -// preferRegExp set to true. -JS::StmtNode *JS::Parser::parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState) -{ - uint32 pos = t->getPos(); - NodeQueue attributes; - while (t->getFlag(Token::isAttribute)) { - attributes += new(arena) IdentifierList(t->getIdentifier()); - t = &lexer.get(false); - if (lineBreakBefore(*t)) - syntaxError("Line break not allowed here"); - } - - switch (as) { - case asAny: - break; - - case asBlock: - if (!t->hasKind(Token::openBrace)) - syntaxError("'{' expected"); - break; - - case asConstVar: - if (!t->hasKind(Token::Const) && !t->hasKind(Token::Var)) - syntaxError("const or var expected"); - break; - } - return parseAttributeStatement(pos, attributes.first, *t, as == asConstVar, semicolonState); -} - - +// If the second token was peeked, it should be have been done with +// preferRegExp set to false; the second token should have been peeked only +// if t is an attribute. +// After parseAttributesAndStatement finishes, the next token might have +// been peeked with preferRegExp set to true. + StmtNode * + Parser::parseAttributesAndStatement(const Token *t, AttributeStatement as, + SemicolonState &semicolonState) + { + uint32 pos = t->getPos(); + NodeQueue attributes; + while (t->getFlag(Token::isAttribute)) { + attributes += new(arena) IdentifierList(t->getIdentifier()); + t = &lexer.get(false); + if (lineBreakBefore(*t)) + syntaxError("Line break not allowed here"); + } + + switch (as) { + case asAny: + break; + + case asBlock: + if (!t->hasKind(Token::openBrace)) + syntaxError("'{' expected"); + break; + + case asConstVar: + if (!t->hasKind(Token::Const) && !t->hasKind(Token::Var)) + syntaxError("const or var expected"); + break; + } + return parseAttributeStatement(pos, attributes.first, *t, + as == asConstVar, semicolonState); + } + + // Parse and return an AnnotatedBlock. -JS::StmtNode *JS::Parser::parseAnnotatedBlock() -{ - const Token &t = lexer.get(true); - SemicolonState semicolonState; + StmtNode * + Parser::parseAnnotatedBlock() + { + const Token &t = lexer.get(true); + SemicolonState semicolonState; - // If package is the first attribute then it must be the only attribute. - if (t.hasKind(Token::Package) && !lexer.peek(false).hasKind(Token::openBrace)) - syntaxError("'{' expected", 0); - return parseAttributesAndStatement(&t, asBlock, semicolonState); -} + // If package is the first attribute then it must be the only + // attribute. + if (t.hasKind(Token::Package) && + !lexer.peek(false).hasKind(Token::openBrace)) + syntaxError("'{' expected", 0); + return parseAttributesAndStatement(&t, asBlock, semicolonState); + } -// Parse and return a ForStatement. The 'for' token has already been read; its position is pos. -// If the statement ends with an optional semicolon, that semicolon is not parsed. -// Instead, parseFor returns a semicolonState with the same meaning as that in parseStatement. +// Parse and return a ForStatement. The 'for' token has already been read; +// its position is pos. If the statement ends with an optional semicolon, +// that semicolon is not parsed. Instead, parseFor returns a semicolonState +// with the same meaning as that in parseStatement. // -// After parseFor finishes, the next token might have been peeked with preferRegExp set to true. -JS::StmtNode *JS::Parser::parseFor(uint32 pos, SemicolonState &semicolonState) -{ - require(true, Token::openParenthesis); - const Token &t = lexer.get(true); - uint32 tPos = t.getPos(); - const Token *t2; - StmtNode *initializer = 0; - ExprNode *expr1 = 0; - ExprNode *expr2 = 0; - ExprNode *expr3 = 0; - StmtNode::Kind sKind = StmtNode::For; - - switch (t.getKind()) { - case Token::semicolon: - goto threeExpr; - - case Token::Const: - case Token::Var: - case Token::Final: - case Token::Static: - case Token::Volatile: - makeAttribute: - initializer = parseAttributesAndStatement(&t, asConstVar, semicolonState); - break; - - case CASE_TOKEN_ATTRIBUTE_IDENTIFIER: - case Token::Public: - case Token::Package: - case Token::Private: - t2 = &lexer.peek(false); - if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowAttribute)) - goto makeAttribute; - default: - lexer.unget(); - expr1 = parseExpression(true); - initializer = new(arena) ExprStmtNode(tPos, StmtNode::expression, expr1); - lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token. - break; - } - - if (lexer.eat(true, Token::semicolon)) - threeExpr: { - if (!lexer.eat(true, Token::semicolon)) { - expr2 = parseExpression(false); - require(false, Token::semicolon); - } - if (lexer.peek(true).hasKind(Token::closeParenthesis)) - lexer.redesignate(false); // Safe: the token is ')'. - else - expr3 = parseExpression(false); - } - else if (lexer.eat(true, Token::In)) { - sKind = StmtNode::ForIn; - if (expr1) { - ASSERT(initializer->hasKind(StmtNode::expression)); - ensurePostfix(expr1); - } else { - ASSERT(initializer->hasKind(StmtNode::Const) || initializer->hasKind(StmtNode::Var)); - const VariableBinding *bindings = static_cast(initializer)->bindings; - if (!bindings || bindings->next) - syntaxError("Only one variable binding can be used in a for-in statement", 0); - } - expr2 = parseExpression(false); - } - else - syntaxError("';' or 'in' expected", 0); - - require(false, Token::closeParenthesis); - return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, parseStatement(false, false, semicolonState)); -} - - -// Parse and return a TryStatement. The 'try' token has already been read; its position is pos. -// After parseTry finishes, the next token might have been peeked with preferRegExp set to true. -JS::StmtNode *JS::Parser::parseTry(uint32 pos) -{ - StmtNode *tryBlock = parseAnnotatedBlock(); - NodeQueue catches; - const Token *t; - - while ((t = lexer.eat(true, Token::Catch)) != 0) { - uint32 catchPos = t->getPos(); - require(true, Token::openParenthesis); - ExprNode *type; - const StringAtom &name = parseTypedIdentifier(type); - require(false, Token::closeParenthesis); - catches += new(arena) CatchClause(catchPos, name, type, parseAnnotatedBlock()); - } - StmtNode *finally = 0; - if (lexer.eat(true, Token::Finally)) - finally = parseAnnotatedBlock(); - else if (!catches.first) - syntaxError("A try statement must be followed by at least one catch or finally", 0); - - return new(arena) TryStmtNode(pos, tryBlock, catches.first, finally); -} - - -// Parse and return a TopStatement. If topLevel is false, allow only Statements. +// After parseFor finishes, the next token might have been peeked with +// preferRegExp set to true. + StmtNode * + Parser::parseFor(uint32 pos, SemicolonState &semicolonState) + { + require(true, Token::openParenthesis); + const Token &t = lexer.get(true); + uint32 tPos = t.getPos(); + const Token *t2; + StmtNode *initializer = 0; + ExprNode *expr1 = 0; + ExprNode *expr2 = 0; + ExprNode *expr3 = 0; + StmtNode::Kind sKind = StmtNode::For; + + switch (t.getKind()) { + case Token::semicolon: + goto threeExpr; + + case Token::Const: + case Token::Var: + case Token::Final: + case Token::Static: + case Token::Volatile: + makeAttribute: + initializer = parseAttributesAndStatement(&t, asConstVar, + semicolonState); + break; + + case CASE_TOKEN_NONRESERVED: + case Token::Public: + case Token::Package: + case Token::Private: + t2 = &lexer.peek(false); + if (!lineBreakBefore(*t2) && + t2->getFlag(Token::canFollowAttribute)) + goto makeAttribute; + default: + lexer.unget(); + expr1 = parseExpression(true); + initializer = new(arena) ExprStmtNode(tPos, + StmtNode::expression, + expr1); + lexer.redesignate(true); // Safe: a '/' or a '/=' would have + // been interpreted as an operator, + // so it can't be the next token. + break; + } + + if (lexer.eat(true, Token::semicolon)) + threeExpr: { + if (!lexer.eat(true, Token::semicolon)) { + expr2 = parseExpression(false); + require(false, Token::semicolon); + } + if (lexer.peek(true).hasKind(Token::closeParenthesis)) + lexer.redesignate(false); // Safe: the token is ')'. + else + expr3 = parseExpression(false); + } + else if (lexer.eat(true, Token::In)) { + sKind = StmtNode::ForIn; + if (expr1) { + ASSERT(initializer->hasKind(StmtNode::expression)); + ensurePostfix(expr1); + } else { + ASSERT(initializer->hasKind(StmtNode::Const) || + initializer->hasKind(StmtNode::Var)); + const VariableBinding *bindings = + static_cast(initializer)->bindings; + if (!bindings || bindings->next) + syntaxError("Only one variable binding can be used in a " + "for-in statement", 0); + } + expr2 = parseExpression(false); + } + else + syntaxError("';' or 'in' expected", 0); + + require(false, Token::closeParenthesis); + return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, + parseStatement(false, false, + semicolonState)); + } + + +// Parse and return a TryStatement. The 'try' token has already been read; +// its position is pos. After parseTry finishes, the next token might have +// been peeked with preferRegExp set to true. + StmtNode * + Parser::parseTry(uint32 pos) + { + StmtNode *tryBlock = parseAnnotatedBlock(); + NodeQueue catches; + const Token *t; + + while ((t = lexer.eat(true, Token::Catch)) != 0) { + uint32 catchPos = t->getPos(); + require(true, Token::openParenthesis); + ExprNode *type; + const StringAtom &name = parseTypedIdentifier(type); + require(false, Token::closeParenthesis); + catches += new(arena) CatchClause(catchPos, name, type, + parseAnnotatedBlock()); + } + StmtNode *finally = 0; + if (lexer.eat(true, Token::Finally)) + finally = parseAnnotatedBlock(); + else if (!catches.first) + syntaxError("A try statement must be followed by at least one " + "catch or finally", 0); + + return new(arena) TryStmtNode(pos, tryBlock, catches.first, finally); + } + + +// Parse and return a TopStatement. If topLevel is false, allow only +// Statements. // If inSwitch is true, allow case : and default: statements. // -// If the statement ends with an optional semicolon, that semicolon is not parsed. +// If the statement ends with an optional semicolon, that semicolon is not +// parsed. // Instead, parseStatement returns in semicolonState one of three values: -// semiNone: No semicolon is needed to close the statement -// semiNoninsertable: A NoninsertableSemicolon is needed to close the statement; a line break is not enough -// semiInsertable: A Semicolon is needed to close the statement; a line break is also sufficient +// semiNone: No semicolon is needed to close the statement +// semiNoninsertable: A NoninsertableSemicolon is needed to close the +// statement; a line break is not enough +// semiInsertable: A Semicolon is needed to close the statement; a +// line break is also sufficient // -// If the first token was peeked, it should be have been done with preferRegExp set to true. -// After parseStatement finishes, the next token might have been peeked with preferRegExp set to true. -JS::StmtNode *JS::Parser::parseStatement(bool /*topLevel*/, bool inSwitch, SemicolonState &semicolonState) -{ - StmtNode *s; - ExprNode *e = 0; - StmtNode::Kind sKind; - const Token &t = lexer.get(true); - const Token *t2; - uint32 pos = t.getPos(); - semicolonState = semiNone; - - checkStackSize(); - switch (t.getKind()) { - case Token::semicolon: - s = new(arena) StmtNode(pos, StmtNode::empty); - break; - - case Token::Constructor: - case Token::Namespace: - t2 = &lexer.peek(false); - if (lineBreakBefore(*t2) || !t2->hasIdentifierKind()) - goto makeExpression; - case Token::openBrace: - case Token::Const: - case Token::Var: - case Token::Function: - case Token::Class: - case Token::Interface: - s = parseAttributeStatement(pos, 0, t, false, semicolonState); - break; - - case Token::If: - e = parseParenthesizedExpression(); - s = parseStatementAndSemicolon(semicolonState); - if (lexer.eat(true, Token::Else)) - s = new(arena) BinaryStmtNode(pos, StmtNode::IfElse, e, s, parseStatement(false, false, semicolonState)); - else { - sKind = StmtNode::If; - goto makeUnary; - } - break; - - case Token::Switch: - e = parseParenthesizedExpression(); - require(true, Token::openBrace); - s = new(arena) SwitchStmtNode(pos, e, parseBlock(true, false)); - break; - - case Token::Case: - if (!inSwitch) - goto notInSwitch; - e = parseExpression(false); - makeSwitchCase: - require(false, Token::colon); - s = new(arena) ExprStmtNode(pos, StmtNode::Case, e); - break; - - case Token::Default: - if (inSwitch) - goto makeSwitchCase; - notInSwitch: - syntaxError("case and default may only be used inside a switch statement"); - break; - - case Token::Do: - { - SemicolonState semiState2; - s = parseStatementAndSemicolon(semiState2); // Ignore semiState2. - require(true, Token::While); - e = parseParenthesizedExpression(); - sKind = StmtNode::DoWhile; - goto makeUnary; - } - break; - - case Token::With: - sKind = StmtNode::With; - goto makeWhileWith; - - case Token::While: - sKind = StmtNode::While; - makeWhileWith: - e = parseParenthesizedExpression(); - s = parseStatement(false, false, semicolonState); - makeUnary: - s = new(arena) UnaryStmtNode(pos, sKind, e, s); - break; - - case Token::For: - s = parseFor(pos, semicolonState); - break; - - case Token::Continue: - sKind = StmtNode::Continue; - goto makeGo; - - case Token::Break: - sKind = StmtNode::Break; - makeGo: - { - const StringAtom *label = 0; - t2 = &lexer.peek(true); - if (t2->hasKind(Token::identifier) && !lineBreakBefore(*t2)) { - lexer.get(true); - label = &t2->getIdentifier(); - } - s = new(arena) GoStmtNode(pos, sKind, label); - } - goto insertableSemicolon; - - case Token::Return: - sKind = StmtNode::Return; - t2 = &lexer.peek(true); - if (lineBreakBefore(*t2) || t2->getFlag(Token::canFollowReturn)) - goto makeExprStmtNode; - goto makeExpressionNode; - - case Token::Throw: - sKind = StmtNode::Throw; - if (lineBreakBefore()) - syntaxError("throw cannot be followed by a line break", 0); - goto makeExpressionNode; - - case Token::Try: - s = parseTry(pos); - break; - - case Token::Debugger: - s = new(arena) DebuggerStmtNode(pos, StmtNode::Debugger); - break; - - case Token::Final: - case Token::Static: - case Token::Volatile: - makeAttribute: - s = parseAttributesAndStatement(&t, asAny, semicolonState); - break; - - case Token::Public: - case Token::Package: - case Token::Private: - t2 = &lexer.peek(false); - goto makeExpressionOrAttribute; - - case CASE_TOKEN_ATTRIBUTE_IDENTIFIER: - t2 = &lexer.peek(false); - if (t2->hasKind(Token::colon)) { - lexer.get(false); - const StringAtom &name = t.getIdentifier(); // Must do this now because parseStatement can invalidate t. - s = new(arena) LabelStmtNode(pos, name, parseStatement(false, false, semicolonState)); - break; - } - makeExpressionOrAttribute: - if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowAttribute)) - goto makeAttribute; - default: - makeExpression: - lexer.unget(); - sKind = StmtNode::expression; - makeExpressionNode: - e = parseExpression(false); - lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token. - makeExprStmtNode: - s = new(arena) ExprStmtNode(pos, sKind, e); - insertableSemicolon: - semicolonState = semiInsertable; - break; - } - return s; -} - - -// Same as parseStatement but also swallow the following semicolon if one is present. -JS::StmtNode *JS::Parser::parseStatementAndSemicolon(SemicolonState &semicolonState) -{ - StmtNode *s = parseStatement(false, false, semicolonState); - if (semicolonState != semiNone && lexer.eat(true, Token::semicolon)) - semicolonState = semiNone; - return s; -} +// If the first token was peeked, it should be have been done with +// preferRegExp set to true. +// After parseStatement finishes, the next token might have been peeked with +// preferRegExp set to true. + StmtNode * + Parser::parseStatement(bool /*topLevel*/, bool inSwitch, + SemicolonState &semicolonState) + { + StmtNode *s; + ExprNode *e = 0; + StmtNode::Kind sKind; + const Token &t = lexer.get(true); + const Token *t2; + uint32 pos = t.getPos(); + semicolonState = semiNone; + checkStackSize(); + switch (t.getKind()) { + case Token::semicolon: + s = new(arena) StmtNode(pos, StmtNode::empty); + break; + + case Token::Namespace: + t2 = &lexer.peek(false); + if (lineBreakBefore(*t2) || !t2->hasIdentifierKind()) + goto makeExpression; + case Token::openBrace: + case Token::Const: + case Token::Var: + case Token::Function: + case Token::Class: + case Token::Interface: + s = parseAttributeStatement(pos, 0, t, false, semicolonState); + break; + + case Token::If: + e = parseParenthesizedExpression(); + s = parseStatementAndSemicolon(semicolonState); + if (lexer.eat(true, Token::Else)) + s = new(arena) BinaryStmtNode(pos, StmtNode::IfElse, e, s, + parseStatement(false, false, + semicolonState)); + else { + sKind = StmtNode::If; + goto makeUnary; + } + break; + + case Token::Switch: + e = parseParenthesizedExpression(); + require(true, Token::openBrace); + s = new(arena) SwitchStmtNode(pos, e, parseBlock(true, false)); + break; + + case Token::Case: + if (!inSwitch) + goto notInSwitch; + e = parseExpression(false); + makeSwitchCase: + require(false, Token::colon); + s = new(arena) ExprStmtNode(pos, StmtNode::Case, e); + break; + + case Token::Default: + if (inSwitch) + goto makeSwitchCase; + notInSwitch: + syntaxError("case and default may only be used inside a " + "switch statement"); + break; + + case Token::Do: + { + SemicolonState semiState2; + // Ignore semiState2. + s = parseStatementAndSemicolon(semiState2); + require(true, Token::While); + e = parseParenthesizedExpression(); + sKind = StmtNode::DoWhile; + goto makeUnary; + } + break; + + case Token::With: + sKind = StmtNode::With; + goto makeWhileWith; + + case Token::While: + sKind = StmtNode::While; + makeWhileWith: + e = parseParenthesizedExpression(); + s = parseStatement(false, false, semicolonState); + makeUnary: + s = new(arena) UnaryStmtNode(pos, sKind, e, s); + break; + + case Token::For: + s = parseFor(pos, semicolonState); + break; + + case Token::Continue: + sKind = StmtNode::Continue; + goto makeGo; + + case Token::Break: + sKind = StmtNode::Break; + makeGo: + { + const StringAtom *label = 0; + t2 = &lexer.peek(true); + if (t2->hasKind(Token::identifier) && + !lineBreakBefore(*t2)) { + lexer.get(true); + label = &t2->getIdentifier(); + } + s = new(arena) GoStmtNode(pos, sKind, label); + } + goto insertableSemicolon; + + case Token::Return: + sKind = StmtNode::Return; + t2 = &lexer.peek(true); + if (lineBreakBefore(*t2) || + t2->getFlag(Token::canFollowReturn)) + goto makeExprStmtNode; + goto makeExpressionNode; + + case Token::Throw: + sKind = StmtNode::Throw; + if (lineBreakBefore()) + syntaxError("throw cannot be followed by a line break", 0); + goto makeExpressionNode; + + case Token::Try: + s = parseTry(pos); + break; + + case Token::Debugger: + s = new(arena) DebuggerStmtNode(pos, StmtNode::Debugger); + break; + + case Token::Final: + case Token::Static: + case Token::Volatile: + makeAttribute: + s = parseAttributesAndStatement(&t, asAny, semicolonState); + break; + + case Token::Public: + case Token::Package: + case Token::Private: + t2 = &lexer.peek(false); + goto makeExpressionOrAttribute; + + case CASE_TOKEN_NONRESERVED: + t2 = &lexer.peek(false); + if (t2->hasKind(Token::colon)) { + lexer.get(false); + // Must do this now because parseStatement can + // invalidate t. + const StringAtom &name = t.getIdentifier(); + s = new(arena) LabelStmtNode(pos, name, + parseStatement(false, false, + semicolonState)); + break; + } + makeExpressionOrAttribute: + if (!lineBreakBefore(*t2) && + t2->getFlag(Token::canFollowAttribute)) + goto makeAttribute; + default: + makeExpression: + lexer.unget(); + sKind = StmtNode::expression; + makeExpressionNode: + e = parseExpression(false); + // Safe: a '/' or a '/=' would have been interpreted as an + // operator, so it can't be the next token. + lexer.redesignate(true); + makeExprStmtNode: + s = new(arena) ExprStmtNode(pos, sKind, e); + insertableSemicolon: + semicolonState = semiInsertable; + break; + } + return s; + } + + +// Same as parseStatement but also swallow the following semicolon if one +// is present. + StmtNode * + Parser::parseStatementAndSemicolon(SemicolonState &semicolonState) + { + StmtNode *s = parseStatement(false, false, semicolonState); + if (semicolonState != semiNone && lexer.eat(true, Token::semicolon)) + semicolonState = semiNone; + return s; + } + // BEGIN NEW CODE -bool JS::Parser::lookahead(Token::Kind kind, bool preferRegExp) { - const Token &t = lexer.peek(preferRegExp); - if (t.getKind() != kind) - return false; - return true; -} - -const JS::Token *JS::Parser::match(Token::Kind kind, bool preferRegExp) { - const Token *t = lexer.eat(preferRegExp,kind); - if (!t || t->getKind() != kind) - return 0; - return t; -} - + bool + Parser::lookahead(Token::Kind kind, bool preferRegExp) + { + const Token &t = lexer.peek(preferRegExp); + if (t.getKind() != kind) + return false; + return true; + } + + const Token * + Parser::match(Token::Kind kind, bool preferRegExp) + { + const Token *t = lexer.eat(preferRegExp,kind); + if (!t || t->getKind() != kind) + return 0; + return t; + } + /** - * Identifier + * Identifier * Identifier * get * set */ + + ExprNode * + Parser::parseIdentifier() + { -JS::ExprNode *JS::Parser::parseIdentifier() { - - ExprNode *result = NULL; - - if( lookahead(Token::Get) ) { - result = NodeFactory::Identifier(*match(Token::Get)); - } else if( lookahead(Token::Set) ) { - result = NodeFactory::Identifier(*match(Token::Set)); - } else if( lookahead(Token::identifier) ) { - result = NodeFactory::Identifier(*match(Token::identifier)); - } else { - // throw new Exception("Expecting an Identifier when encountering input: " + scanner.getErrorText()); + ExprNode *result = NULL; + + if(lookahead(Token::Get)) { + result = NodeFactory::Identifier(*match(Token::Get)); + } else if(lookahead(Token::Set)) { + result = NodeFactory::Identifier(*match(Token::Set)); + } else if(lookahead(Token::identifier)) { + result = NodeFactory::Identifier(*match(Token::identifier)); + } else { + // throw new Exception("Expecting an Identifier when encountering " + // "input: " + scanner.getErrorText()); + } + + return result; } - - return result; -} - + /** - * LiteralField + * LiteralField * FieldName : AssignmentExpressionallowIn */ -JS::ExprPairList *JS::Parser::parseLiteralField() { + ExprPairList * + Parser::parseLiteralField() + { - ExprPairList *result=NULL; - ExprNode *first; - ExprNode *second; + ExprPairList *result=NULL; + ExprNode *first; + ExprNode *second; - first = parseFieldName(); - match(Token::colon); - second = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - result = NodeFactory::LiteralField(first,second); - - return result; -} + first = parseFieldName(); + match(Token::colon); + second = parseAssignmentExpression(); + lexer.redesignate(true); // Safe: looking for non-slash punctuation. + result = NodeFactory::LiteralField(first,second); + + return result; + } /** - * FieldName + * FieldName * Identifier * String * Number * ParenthesizedExpression */ -JS::ExprNode *JS::Parser::parseFieldName() { + ExprNode * + Parser::parseFieldName() + { - ExprNode *result; + ExprNode *result; - if( lookahead(Token::string) ) { - const Token *t = match(Token::string); - result = NodeFactory::LiteralString(t->getPos(),ExprNode::string,copyTokenChars(*t)); - } else if( lookahead(Token::number) ) { - const Token *t = match(Token::number); - result = NodeFactory::LiteralNumber(*t); - } else if( lookahead(Token::openParenthesis) ) { - result = parseParenthesizedExpression(); - } else { - result = parseIdentifier(); + if( lookahead(Token::string) ) { + const Token *t = match(Token::string); + result = NodeFactory::LiteralString(t->getPos(), ExprNode::string, + copyTokenChars(*t)); + } else if(lookahead(Token::number)) { + const Token *t = match(Token::number); + result = NodeFactory::LiteralNumber(*t); + } else if( lookahead(Token::openParenthesis) ) { + result = parseParenthesizedExpression(); + } else { + result = parseIdentifier(); + } + + return result; } - return result; -} - /** - * ArgumentList - * «empty» + * ArgumentList + * * LiteralField NamedArgumentListPrime * AssignmentExpression[allowIn] ArgumentListPrime */ -JS::ExprPairList *JS::Parser::parseArgumentList(NodeQueue &args) { + ExprPairList * + Parser::parseArgumentList(NodeQueue &args) + { - ExprPairList *result=NULL; + ExprPairList *result=NULL; - if( lookahead(Token::closeParenthesis) ) { - } else { - ExprNode *first; - first = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - //if( AssignmentExpressionNode.isFieldName(first) && lookahead(colon_token) ) { - if( lookahead(Token::colon) ) { - ExprNode *second; - match(Token::colon); - // Finish parsing the LiteralField. - second = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - args += NodeFactory::LiteralField(first,second); - result = parseNamedArgumentListPrime(args); + if (lookahead(Token::closeParenthesis)) { } else { - args += NodeFactory::LiteralField(NULL,first); - result = parseArgumentListPrime(args); + ExprNode *first; + first = parseAssignmentExpression(); + lexer.redesignate(true); //Safe: looking for non-slash punctuation. + //if( AssignmentExpressionNode.isFieldName(first) && + //lookahead(colon_token) ) { + if( lookahead(Token::colon) ) { + ExprNode *second; + match(Token::colon); + // Finish parsing the LiteralField. + second = parseAssignmentExpression(); + // Safe: looking for non-slash punctuation. + lexer.redesignate(true); + args += NodeFactory::LiteralField(first,second); + result = parseNamedArgumentListPrime(args); + } else { + args += NodeFactory::LiteralField(NULL,first); + result = parseArgumentListPrime(args); + } } + return result; } - return result; -} /** - * ArgumentListPrime - * «empty» + * ArgumentListPrime + * * , AssignmentExpression[allowIn] ArgumentListPrime * , LiteralField NamedArgumentListPrime */ -JS::ExprPairList *JS::Parser::parseArgumentListPrime(NodeQueue &args) { + ExprPairList * + Parser::parseArgumentListPrime(NodeQueue &args) + { - ExprPairList *result; + ExprPairList *result; + + if(lookahead(Token::comma)) { - if( lookahead(Token::comma) ) { - - match(Token::comma); - ExprNode *first; - first = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - //if( AssignmentExpressionNode.isFieldName(second) && lookahead(colon_token) ) { - if( lookahead(Token::colon) ) { - ExprNode *second; - - match(Token::colon); - - // Finish parsing the literal field. + match(Token::comma); + ExprNode *first; + first = parseAssignmentExpression(); + lexer.redesignate(true); //Safe: looking for non-slash punctuation. + //if( AssignmentExpressionNode.isFieldName(second) && + // lookahead(colon_token) ) { + if( lookahead(Token::colon) ) { + ExprNode *second; + + match(Token::colon); + // Finish parsing the literal field. + second = parseAssignmentExpression(); + // Safe: looking for non-slash punctuation. + lexer.redesignate(true); + args += NodeFactory::LiteralField(first,second); + result = parseNamedArgumentListPrime(args); + + } else { + args += NodeFactory::LiteralField(NULL,first); + result = parseArgumentListPrime(args); + + } - second = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - args += NodeFactory::LiteralField(first,second); - result = parseNamedArgumentListPrime(args); - } else { - args += NodeFactory::LiteralField(NULL,first); - result = parseArgumentListPrime(args); - + result = args.first; } - - } else { - result = args.first; + + return result; } - - return result; -} - + /** - * NamedArgumentListPrime - * «empty» + * NamedArgumentListPrime + * * , LiteralField NamedArgumentListPrime */ -JS::ExprPairList *JS::Parser::parseNamedArgumentListPrime(NodeQueue &args) { + ExprPairList * + Parser::parseNamedArgumentListPrime(NodeQueue &args) + { - ExprPairList *result; - - if( lookahead(Token::comma) ) { - match(Token::comma); - args += parseLiteralField(); - result = parseNamedArgumentListPrime(args); - } else { - result = args.first; + ExprPairList *result; + + if(lookahead(Token::comma)) { + match(Token::comma); + args += parseLiteralField(); + result = parseNamedArgumentListPrime(args); + } else { + result = args.first; + } + + return result; } - - return result; -} - + /** - * AllParameters + * AllParameters * Parameter * Parameter , AllParameters * Parameter OptionalParameterPrime @@ -3642,51 +1922,54 @@ JS::ExprPairList *JS::Parser::parseNamedArgumentListPrime(NodeQueue ¶ms) { + VariableBinding * + Parser::parseAllParameters(FunctionDefinition &fd, + NodeQueue ¶ms) + { - VariableBinding *result; + VariableBinding *result; - if( lookahead(Token::tripleDot) ) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - if( lookahead(Token::comma) ) { - match(Token::comma); - match(Token::bitwiseOr); - result = parseNamedParameters(fd,params); - } else { - result = params.first; - } - } else if( lookahead(Token::bitwiseOr) ) { - match(Token::bitwiseOr); - result = parseNamedRestParameters(fd,params); - } else { - VariableBinding *first; - first = parseParameter(); - if( lookahead(Token::comma) ) { - params += first; - match(Token::comma); - result = parseAllParameters(fd,params); - } else if( lookahead(Token::assignment) ) { - first = parseOptionalParameterPrime(first); - if (!fd.optParameters) { - fd.optParameters = first; - } - params += first; + if(lookahead(Token::tripleDot)) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; if( lookahead(Token::comma) ) { match(Token::comma); - result = parseOptionalNamedRestParameters(fd,params); - } + match(Token::bitwiseOr); + result = parseNamedParameters(fd,params); + } else { + result = params.first; + } + } else if( lookahead(Token::bitwiseOr) ) { + match(Token::bitwiseOr); + result = parseNamedRestParameters(fd,params); } else { - params += first; - result = params.first; + VariableBinding *first; + first = parseParameter(); + if( lookahead(Token::comma) ) { + params += first; + match(Token::comma); + result = parseAllParameters(fd,params); + } else if( lookahead(Token::assignment) ) { + first = parseOptionalParameterPrime(first); + if (!fd.optParameters) { + fd.optParameters = first; + } + params += first; + if( lookahead(Token::comma) ) { + match(Token::comma); + result = parseOptionalNamedRestParameters(fd,params); + } + } else { + params += first; + result = params.first; + } } + + return result; } - - return result; -} - + /** - * OptionalNamedRestParameters + * OptionalNamedRestParameters * OptionalParameter * OptionalParameter , OptionalNamedRestParameters * | NamedRestParameters @@ -3694,59 +1977,102 @@ JS::VariableBinding *JS::Parser::parseAllParameters(FunctionDefinition &fd,NodeQ * RestParameter , | NamedParameters */ -JS::VariableBinding *JS::Parser::parseOptionalNamedRestParameters(FunctionDefinition &fd,NodeQueue ¶ms) { + VariableBinding * + Parser::parseOptionalNamedRestParameters (FunctionDefinition &fd, + NodeQueue ¶ms) + { - VariableBinding *result; + VariableBinding *result; - if( lookahead(Token::tripleDot) ) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - if( lookahead(Token::comma) ) { - match(Token::comma); + if( lookahead(Token::tripleDot) ) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; + if( lookahead(Token::comma) ) { + match(Token::comma); + match(Token::bitwiseOr); + result = parseNamedParameters(fd,params); + } else { + result = params.first; + } + } else if( lookahead(Token::bitwiseOr) ) { match(Token::bitwiseOr); - result = parseNamedParameters(fd,params); + result = parseNamedRestParameters(fd,params); } else { - result = params.first; + VariableBinding *first; + first = parseOptionalParameter(); + if (!fd.optParameters) { + fd.optParameters = first; + } + params += first; + if( lookahead(Token::comma) ) { + match(Token::comma); + result = parseOptionalNamedRestParameters(fd,params); + } else { + result = params.first; + } } - } else if( lookahead(Token::bitwiseOr) ) { - match(Token::bitwiseOr); - result = parseNamedRestParameters(fd,params); - } else { - VariableBinding *first; - first = parseOptionalParameter(); - if (!fd.optParameters) { - fd.optParameters = first; - } - params += first; - if( lookahead(Token::comma) ) { - match(Token::comma); - result = parseOptionalNamedRestParameters(fd,params); - } else { - result = params.first; - } + + return result; } - - return result; -} - + /** - * NamedRestParameters + * NamedRestParameters * NamedParameter * NamedParameter , NamedRestParameters * RestParameter */ -JS::VariableBinding *JS::Parser::parseNamedRestParameters(FunctionDefinition &fd,NodeQueue ¶ms) { + VariableBinding * + Parser::parseNamedRestParameters(FunctionDefinition &fd, + NodeQueue ¶ms) + { - VariableBinding *result; + VariableBinding *result; - if( lookahead(Token::tripleDot) ) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - result = params.first; - } else { - NodeQueue aliases; - VariableBinding *first; + if (lookahead(Token::tripleDot)) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; + result = params.first; + } else { + NodeQueue aliases; + VariableBinding *first; + first = parseNamedParameter(aliases); + // The following marks the position in the list that named + // parameters may occur. It is not required that this + // particular parameter has + // aliases associated with it. + if (!fd.namedParameters) { + fd.namedParameters = first; + } + if (!fd.optParameters && first->initializer) { + fd.optParameters = first; + } + if( lookahead(Token::comma) ) { + params += first; + match(Token::comma); + result = parseNamedRestParameters(fd,params); + } else { + params += first; + result = params.first; + } + } + + return result; + } + +/** + * NamedParameters + * NamedParameter + * NamedParameter , NamedParameters + */ + + VariableBinding * + Parser::parseNamedParameters(FunctionDefinition &fd, + NodeQueue ¶ms) + { + + VariableBinding *result,*first; + NodeQueue aliases; // List of aliases. first = parseNamedParameter(aliases); // The following marks the position in the list that named parameters // may occur. It is not required that this particular parameter has @@ -3757,173 +2083,990 @@ JS::VariableBinding *JS::Parser::parseNamedRestParameters(FunctionDefinition &fd if (!fd.optParameters && first->initializer) { fd.optParameters = first; } - if( lookahead(Token::comma) ) { + if (lookahead(Token::comma)) { params += first; match(Token::comma); - result = parseNamedRestParameters(fd,params); + result = parseNamedParameters(fd,params); } else { params += first; result = params.first; } + + return result; } - - return result; -} - + /** - * NamedParameters - * NamedParameter - * NamedParameter , NamedParameters - */ - -JS::VariableBinding *JS::Parser::parseNamedParameters(FunctionDefinition &fd,NodeQueue ¶ms) { - - VariableBinding *result,*first; - NodeQueue aliases; // List of aliases. - first = parseNamedParameter(aliases); - // The following marks the position in the list that named parameters - // may occur. It is not required that this particular parameter has - // aliases associated with it. - if (!fd.namedParameters) { - fd.namedParameters = first; - } - if (!fd.optParameters && first->initializer) { - fd.optParameters = first; - } - if (lookahead(Token::comma)) { - params += first; - match(Token::comma); - result = parseNamedParameters(fd,params); - } else { - params += first; - result = params.first; - } - - return result; -} - -/** - * RestParameter + * RestParameter * ... * ... Parameter */ -JS::VariableBinding *JS::Parser::parseRestParameter() { + VariableBinding * + Parser::parseRestParameter() + { - VariableBinding *result; - - match(Token::tripleDot); - if( lookahead(Token::identifier) || - lookahead(Token::Get) || - lookahead(Token::Set) ) { - result = parseParameter(); - } else { - result = NodeFactory::Parameter(0,0); + VariableBinding *result; + + match(Token::tripleDot); + if (lookahead(Token::closeParenthesis) || + lookahead(Token::comma)) { + result = NodeFactory::Parameter(0, 0, false); + } else { + result = parseParameter(); + } + + return result; } - - return result; -} - + /** - * Parameter + * Parameter * Identifier * Identifier : TypeExpression[allowIn] */ -JS::VariableBinding *JS::Parser::parseParameter() { - - VariableBinding *result=NULL; - ExprNode *first,*second; - - first = parseIdentifier(); - if( lookahead(Token::colon) ) { - match(Token::colon); - second = parseTypeExpression(); - } else { - second = NULL; + VariableBinding * + Parser::parseParameter() + { + bool constant = lexer.eat (true, Token::Const); + ExprNode *first = parseIdentifier(); + ExprNode *second = parseTypeBinding (Token::colon, false); + + return NodeFactory::Parameter(first, second, constant); } - - result = NodeFactory::Parameter(first,second); - - return result; -} - + /** - * OptionalParameter + * OptionalParameter * Parameter = AssignmentExpression[allowIn] */ -JS::VariableBinding *JS::Parser::parseOptionalParameter() { + VariableBinding * + Parser::parseOptionalParameter() + { - VariableBinding *result,*first; + VariableBinding *result,*first; + + first = parseParameter(); + result = parseOptionalParameterPrime(first); + + return result; + } - first = parseParameter(); - result = parseOptionalParameterPrime(first); + VariableBinding * + Parser::parseOptionalParameterPrime(VariableBinding *first) + { - return result; -} - -JS::VariableBinding *JS::Parser::parseOptionalParameterPrime(VariableBinding *first) { - - VariableBinding* result=NULL; - - match(Token::assignment); - first->initializer = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash puncutation. - result = first; - - return result; -} + VariableBinding* result=NULL; + + match(Token::assignment); + first->initializer = parseAssignmentExpression(); + lexer.redesignate(true); // Safe: looking for non-slash puncutation. + result = first; + + return result; + } /** - * NamedParameter + * NamedParameter * Parameter * OptionalParameter * String NamedParameter */ -JS::VariableBinding *JS::Parser::parseNamedParameter(NodeQueue &aliases) { + VariableBinding * + Parser::parseNamedParameter(NodeQueue &aliases) + { - VariableBinding *result; - - if( lookahead(Token::string) ) { - const Token *t = match(Token::string); - aliases += NodeFactory::ListedIdentifier(copyTokenChars(*t)); - result = parseNamedParameter(aliases); - } else { - result = parseParameter(); - result->aliases = aliases.first; - if( lookahead(Token::assignment) ) { - result = parseOptionalParameterPrime(result); - } + VariableBinding *result; + + if(lookahead(Token::string)) { + const Token *t = match(Token::string); + aliases += NodeFactory::ListedIdentifier(copyTokenChars(*t)); + result = parseNamedParameter(aliases); + } else { + result = parseParameter(); + result->aliases = aliases.first; + if(lookahead(Token::assignment)) { + result = parseOptionalParameterPrime(result); + } + } + return result; } - return result; -} /** - * ResultSignature - * «empty» + * ResultSignature + * * : TypeExpression[allowIn] */ -JS::ExprNode *JS::Parser::parseResultSignature() { + ExprNode * + Parser::parseResultSignature() + { - ExprNode* result=NULL; - - if( lookahead(Token::colon) ) { - match(Token::colon); - result = parseTypeExpression(); // allowIn is default. - } else { - result = NULL; + ExprNode* result=NULL; + + if (lookahead(Token::colon)) + { + match(Token::colon); + result = parseTypeExpression(); // allowIn is default. + } else { + result = NULL; + } + + return result; } - return result; -} + + bool + IdentifierList::contains(Token::Kind kind) + { + if (name.tokenKind == kind) + return true; + else + return (next) ? next->contains(kind) : false; + } + +// +// Parser Utilities +// + + // Print extra parentheses around subexpressions? + const bool debugExprNodePrint = true; + // Size of one level of statement indentation + const int32 basicIndent = 4; + // Indentation before a case or default statement + const int32 caseIndent = basicIndent/2; + // Indentation of var or const statement bindings + const int32 varIndent = 2; + // Size of one level of expression indentation + const int32 subexpressionIndent = 4; + // Indentation of function signature + const int32 functionHeaderIndent = 9; + // Indentation of class, interface, or namespace header + const int32 namespaceHeaderIndent = 4; -bool JS::IdentifierList::contains(Token::Kind kind) { - if (name.tokenKind == kind) - return true; - else - return (next) ? next->contains(kind) : false; + static const char functionPrefixNames[3][5] = {"", "get ", "set " }; + +// Print this onto f. name must be non-nil. + void + FunctionName::print(PrettyPrinter &f) const + { + f << functionPrefixNames[prefix]; + f << name; + } + + +// Print this onto f. if printConst is false, inhibit printing of the +// const keyword. + void + VariableBinding::print(PrettyPrinter &f, bool printConst) const + { + PrettyPrinter::Block b(f); + +#ifdef NEW_PARSER + if (aliases) { + IdentifierList *id = aliases; + f << "| "; + while (id) { + f << "'"; + f << id->name; + f << "' "; + id = id->next; + } + } +#endif + + if (printConst && constant) + f << "const "; + + if (name) + f << name; + PrettyPrinter::Indent i(f, subexpressionIndent); + if (type) { + f.fillBreak(0); + f << ": "; + f << type; + } + if (initializer) { + f.linearBreak(1); + f << "= "; + f << initializer; + } + } + + +// Print this onto f. If attributes is null, this is a function expression; +// if attributes is non-null, this is a function statement with the given +// attributes. +// When there is no function body, print a trailing semicolon unless noSemi is +// true. + void + FunctionDefinition::print(PrettyPrinter &f, + const AttributeStmtNode *attributes, + bool noSemi) const + { + PrettyPrinter::Block b(f); + if (attributes) + attributes->printAttributes(f); + + f << "function"; + + if (name) { + f << ' '; + FunctionName::print(f); + } + { + PrettyPrinter::Indent i(f, functionHeaderIndent); + f.fillBreak(0); + f << '('; + { + PrettyPrinter::Block b2(f); + const VariableBinding *p = parameters; + if (p) + while (true) { + if (p == restParameter) { + f << "..."; + if (p->name) + f << ' '; + } + p->print(f, true); + p = p->next; + if (!p) + break; + f << ','; + f.fillBreak(1); + } + f << ')'; + } + if (resultType) { + f.fillBreak(0); + f << ": "; + f << resultType; + } + } + if (body) { + bool loose = attributes != 0; + f.linearBreak(1, loose); + body->printBlock(f, loose); + } else + StmtNode::printSemi(f, noSemi); + } + +// Print a comma-separated ExprList on to f. Since a method can't be called +// on nil, the list has at least one element. + void + ExprList::printCommaList(PrettyPrinter &f) const + { + PrettyPrinter::Block b(f); + const ExprList *list = this; + while (true) { + f << list->expr; + list = list->next; + if (!list) + break; + f << ','; + f.fillBreak(1); + } + } + + +// If list is nil, do nothing. Otherwise, emit a linear line break of size 1, +// the name, a space, and the contents of list separated by commas. + void + ExprList::printOptionalCommaList(PrettyPrinter &f, const char *name, + const ExprList *list) + { + if (list) { + f.linearBreak(1); + f << name << ' '; + list->printCommaList(f); + } + } + + +// +// ExprNode +// + + const char *const ExprNode::kindNames[kindsEnd] = { + "NIL", // none + 0, // identifier + 0, // number + 0, // string + 0, // regExp + "null", // Null + "true", // True + "false", // False + "this", // This + "super", // Super + + 0, // parentheses + 0, // numUnit + 0, // exprUnit + "::", // qualify + + 0, // objectLiteral + 0, // arrayLiteral + 0, // functionLiteral + + 0, // call + 0, // New + 0, // index + + ".", // dot + ".class", // dotClass + ".(", // dotParen + "@", // at + + "delete ", // Delete + "typeof ", // Typeof + "eval ", // Eval + "++ ", // preIncrement + "-- ", // preDecrement + " ++", // postIncrement + " --", // postDecrement + "+ ", // plus + "- ", // minus + "~ ", // complement + "! ", // logicalNot + + "+", // add + "-", // subtract + "*", // multiply + "/", // divide + "%", // modulo + "<<", // leftShift + ">>", // rightShift + ">>>", // logicalRightShift + "&", // bitwiseAnd + "^", // bitwiseXor + "|", // bitwiseOr + "&&", // logicalAnd + "^^", // logicalXor + "||", // logicalOr + + "==", // equal + "!=", // notEqual + "<", // lessThan + "<=", // lessThanOrEqual + ">", // greaterThan + ">=", // greaterThanOrEqual + "===", // identical + "!==", // notIdentical + "in", // In + "instanceof", // Instanceof + + "=", // assignment + "+=", // addEquals + "-=", // subtractEquals + "*=", // multiplyEquals + "/=", // divideEquals + "%=", // moduloEquals + "<<=", // leftShiftEquals + ">>=", // rightShiftEquals + ">>>=", // logicalRightShiftEquals + "&=", // bitwiseAndEquals + "^=", // bitwiseXorEquals + "|=", // bitwiseOrEquals + "&&=", // logicalAndEquals + "^^=", // logicalXorEquals + "||=", // logicalOrEquals + + "?", // conditional + "," // comma +}; + + +// Print this onto f. + void + ExprNode::print(PrettyPrinter &f) const + { + f << kindName(kind); + } + + void + IdentifierExprNode::print(PrettyPrinter &f) const + { + f << name; + } + + void + NumberExprNode::print(PrettyPrinter &f) const + { + f << value; + } + + void + StringExprNode::print(PrettyPrinter &f) const + { + quoteString(f, str, '"'); + } + + void + RegExpExprNode::print(PrettyPrinter &f) const + { + f << '/' << re << '/' << flags; + } + + void + NumUnitExprNode::print(PrettyPrinter &f) const + { + f << numStr; + StringExprNode::print(f); + } + + void + ExprUnitExprNode::print(PrettyPrinter &f) const + { + f << op; + StringExprNode::print(f); + } + + void + FunctionExprNode::print(PrettyPrinter &f) const + { + function.print(f, 0, false); + } + + void + PairListExprNode::print(PrettyPrinter &f) const + { + char beginBracket; + char endBracket; + + switch (getKind()) { + case objectLiteral: + beginBracket = '{'; + endBracket = '}'; + break; + + case arrayLiteral: + case index: + beginBracket = '['; + endBracket = ']'; + break; + + case call: + case New: + beginBracket = '('; + endBracket = ')'; + break; + + default: + NOT_REACHED("Bad kind"); + return; + } + + f << beginBracket; + PrettyPrinter::Block b(f); + const ExprPairList *p = pairs; + if (p) + while (true) { + const ExprNode *field = p->field; + if (field) { + f << field << ':'; + f.fillBreak(0); + } + + const ExprNode *value = p->value; + if (value) + f << value; + + p = p->next; + if (!p) + break; + f << ','; + f.linearBreak(static_cast(field || value)); + } + f << endBracket; + } + + void + InvokeExprNode::print(PrettyPrinter &f) const + { + PrettyPrinter::Block b(f); + if (hasKind(New)) + f << "new "; + f << op; + PrettyPrinter::Indent i(f, subexpressionIndent); + f.fillBreak(0); + PairListExprNode::print(f); + } + + void + UnaryExprNode::print(PrettyPrinter &f) const + { + if (hasKind(parentheses)) { + f << '('; + f << op; + f << ')'; + } else { + if (debugExprNodePrint) + f << '('; + const char *name = kindName(getKind()); + if (hasKind(postIncrement) || hasKind(postDecrement) || + hasKind(dotClass)) { + f << op; + f << name; + } else { + f << name; + f << op; + } + if (debugExprNodePrint) + f << ')'; + } + } + + void + BinaryExprNode::print(PrettyPrinter &f) const + { + if (debugExprNodePrint && !hasKind(qualify)) + f << '('; + PrettyPrinter::Block b(f); + f << op1; + uint32 nSpaces = hasKind(dot) || hasKind(dotParen) || hasKind(at) || + hasKind(qualify) ? (uint32)0 : (uint32)1; + f.fillBreak(nSpaces); + f << kindName(getKind()); + f.fillBreak(nSpaces); + f << op2; + if (hasKind(dotParen)) + f << ')'; + if (debugExprNodePrint && !hasKind(qualify)) + f << ')'; + } + + void + TernaryExprNode::print(PrettyPrinter &f) const + { + if (debugExprNodePrint) + f << '('; + PrettyPrinter::Block b(f); + f << op1; + f.fillBreak(1); + f << '?'; + f.fillBreak(1); + f << op2; + f.fillBreak(1); + f << ':'; + f.fillBreak(1); + f << op3; + if (debugExprNodePrint) + f << ')'; + } + +// +// StmtNode +// + +// Print statements on separate lines onto f. Do not print a line break +// after the last statement. + void + StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements) + { + if (statements) { + PrettyPrinter::Block b(f); + while (true) { + const StmtNode *next = statements->next; + statements->print(f, !next); + statements = next; + if (!statements) + break; + f.requiredBreak(); + } + } + } + +// Print statements as a block enclosed in curly braces onto f. +// If loose is false, do not insist on each statement being on a separate +// line; instead, make breaks between statements be linear breaks in the +// enclosing PrettyPrinter::Block scope. The caller must have placed this +// call inside a PrettyPrinter::Block scope. + void + StmtNode::printBlockStatements(PrettyPrinter &f, + const StmtNode *statements, bool loose) + { + f << '{'; + if (statements) { + { + PrettyPrinter::Indent i(f, basicIndent); + uint32 nSpaces = 0; + while (statements) { + if (statements->hasKind(Case)) { + PrettyPrinter::Indent i2(f, caseIndent - basicIndent); + f.linearBreak(nSpaces, loose); + statements->print(f, false); + } else { + f.linearBreak(nSpaces, loose); + statements->print(f, !statements->next); + } + statements = statements->next; + nSpaces = 1; + } + } + f.linearBreak(0, loose); + } else + f.fillBreak(0); + f << '}'; + } + + +// Print a closing statement semicolon onto f unless noSemi is true. + void + StmtNode::printSemi(PrettyPrinter &f, bool noSemi) + { + if (!noSemi) + f << ';'; + } + + +// Print this as a substatement of a statement such as if or with. +// If this statement is a block without attributes, begin it on the current +// line and do not indent it -- the block itself will provide the indent. +// Otherwise, begin this statement on a new line and indent it. +// If continuation is non-nil, it specifies a continuation such as 'else' or +// the 'while' of a do-while statement. If this statement is a block without +// attributes, print a space and the continuation after the closing brace; +// otherwise print the continuation on a new line. +// If noSemi is true, do not print the semicolon unless it is required by the +// statement. The caller must have placed this call inside a +// PrettyPrinter::Block scope that encloses the containining statement. + void + StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, + const char *continuation) const + { + if (hasKind(block) && + !static_cast(this)->attributes) { + f << ' '; + static_cast(this)->printBlock(f, true); + if (continuation) + f << ' ' << continuation; + } else { + { + PrettyPrinter::Indent i(f, basicIndent); + f.requiredBreak(); + this->print(f, noSemi); + } + if (continuation) { + f.requiredBreak(); + f << continuation; + } + } + } + + +// Print the attributes on a single line separated with and followed by a +// space. + void AttributeStmtNode::printAttributes(PrettyPrinter &f) const + { + for (const IdentifierList *a = attributes; a; a = a->next) + f << a->name << ' '; + } + + +// Print this block, including attributes, onto f. +// If loose is false, do not insist on each statement being on a separate +// line; instead, make breaks between statements be linear breaks in the +// enclosing PrettyPrinter::Block scope. +// The caller must have placed this call inside a PrettyPrinter::Block scope. + void BlockStmtNode::printBlock(PrettyPrinter &f, bool loose) const + { + printAttributes(f); + printBlockStatements(f, statements, loose); + } + +// Print this onto f. +// If noSemi is true, do not print the trailing semicolon unless it is +// required by the statement. + void + StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const + { + ASSERT(hasKind(empty)); + f << ';'; + } + + void + ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + const ExprNode *e = expr; + + switch (getKind()) { + case Case: + if (e) { + f << "case "; + f << e; + } else + f << "default"; + f << ':'; + break; + + case Return: + f << "return"; + if (e) { + f << ' '; + goto showExpr; + } else + goto showSemicolon; + + case Throw: + f << "throw "; + case expression: + showExpr: + f << e; + showSemicolon: + printSemi(f, noSemi); + break; + + default: + NOT_REACHED("Bad kind"); + } + } + + void + DebuggerStmtNode::print(PrettyPrinter &f, bool) const + { + f << "debugger;"; + } + + void + BlockStmtNode::print(PrettyPrinter &f, bool) const + { + PrettyPrinter::Block b(f, 0); + printBlock(f, true); + } + + void + LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + PrettyPrinter::Block b(f, basicIndent); + f << name << ':'; + f.linearBreak(1); + stmt->print(f, noSemi); + } + + void + UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + PrettyPrinter::Block b(f, 0); + printContents(f, noSemi); + } + +// Same as print except that uses the caller's PrettyPrinter::Block. + void + UnaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const + { + ASSERT(stmt); + const char *kindName = 0; + + switch (getKind()) { + case If: + kindName = "if"; + break; + + case While: + kindName = "while"; + break; + + case DoWhile: + f << "do"; + stmt->printSubstatement(f, true, "while ("); + f << expr << ')'; + printSemi(f, noSemi); + return; + + case With: + kindName = "with"; + break; + + default: + NOT_REACHED("Bad kind"); + } + + f << kindName << " ("; + f << expr << ')'; + stmt->printSubstatement(f, noSemi); + } + + void + BinaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const + { + ASSERT(stmt && stmt2 && hasKind(IfElse)); + + f << "if ("; + f << expr << ')'; + stmt->printSubstatement(f, true, "else"); + if (stmt2->hasKind(If) || stmt2->hasKind(IfElse)) { + f << ' '; + static_cast(stmt2)->printContents(f, + noSemi); + } else + stmt2->printSubstatement(f, noSemi); + } + + void + ForStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + ASSERT(stmt && (hasKind(For) || hasKind(ForIn))); + + PrettyPrinter::Block b(f, 0); + f << "for ("; + { + PrettyPrinter::Block b2(f); + if (initializer) + initializer->print(f, true); + if (hasKind(ForIn)) { + f.fillBreak(1); + f << "in"; + f.fillBreak(1); + ASSERT(expr2 && !expr3); + f << expr2; + } else { + f << ';'; + if (expr2) { + f.linearBreak(1); + f << expr2; + } + f << ';'; + if (expr3) { + f.linearBreak(1); + f << expr3; + } + } + f << ')'; + } + stmt->printSubstatement(f, noSemi); + } + + void + SwitchStmtNode::print(PrettyPrinter &f, bool) const + { + PrettyPrinter::Block b(f); + f << "switch ("; + f << expr << ") "; + printBlockStatements(f, statements, true); + } + + void + GoStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + const char *kindName = 0; + + switch (getKind()) { + case Break: + kindName = "break"; + break; + + case Continue: + kindName = "continue"; + break; + + default: + NOT_REACHED("Bad kind"); + } + + f << kindName; + if (name) + f << " " << *name; + printSemi(f, noSemi); + } + + void + TryStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + PrettyPrinter::Block b(f, 0); + f << "try"; + const StmtNode *s = stmt; + for (const CatchClause *c = catches; c; c = c->next) { + s->printSubstatement(f, true, "catch ("); + PrettyPrinter::Block b2(f); + f << c->name; + ExprNode *t = c->type; + if (t) { + f << ':'; + f.linearBreak(1); + f << t; + } + f << ')'; + s = c->stmt; + } + if (finally) { + s->printSubstatement(f, true, "finally"); + s = finally; + } + s->printSubstatement(f, noSemi); + } + + void + VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + printAttributes(f); + ASSERT(hasKind(Const) || hasKind(Var)); + f << (hasKind(Const) ? "const" : "var"); + { + PrettyPrinter::Block b(f, basicIndent); + const VariableBinding *binding = bindings; + if (binding) + while (true) { + f.linearBreak(1); + binding->print(f, false); + binding = binding->next; + if (!binding) + break; + f << ','; + } + } + printSemi(f, noSemi); + } + + void + FunctionStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + function.print(f, this, noSemi); + } + + void + NamespaceStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + printAttributes(f); + ASSERT(hasKind(Namespace)); + + PrettyPrinter::Block b(f, namespaceHeaderIndent); + f << "namespace "; + f << name; + ExprList::printOptionalCommaList(f, "extends", supers); + printSemi(f, noSemi); + } + + void + ClassStmtNode::print(PrettyPrinter &f, bool noSemi) const + { + printAttributes(f); + ASSERT(hasKind(Class) || hasKind(Interface)); + + { + PrettyPrinter::Block b(f, namespaceHeaderIndent); + const char *keyword; + const char *superlistKeyword; + if (hasKind(Class)) { + keyword = "class "; + superlistKeyword = "implements"; + } else { + keyword = "interface "; + superlistKeyword = "extends"; + } + f << keyword; + f << name; + if (superclass) { + f.linearBreak(1); + f << "extends "; + f << superclass; + } + ExprList::printOptionalCommaList(f, superlistKeyword, supers); + } + if (body) { + f.requiredBreak(); + body->printBlock(f, true); + } else + printSemi(f, noSemi); + } } diff --git a/mozilla/js2/src/parser.h b/mozilla/js2/src/parser.h index 526eaa6dea2..179997e8649 100644 --- a/mozilla/js2/src/parser.h +++ b/mozilla/js2/src/parser.h @@ -1,1091 +1,962 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#ifndef parser_h -#define parser_h +#ifndef parser_h___ +#define parser_h___ +#include "world.h" #include "utilities.h" +#include "reader.h" +#include "lexer.h" #include namespace JavaScript { - class StringAtom; - class World; - -// -// Reader -// - - // A Reader reads Unicode characters from a source string. - // Calling get() yields all of the characters in sequence. One character may be read - // past the end of the source; that character appears as a null. - class Reader { - const char16 *begin; // Beginning of source text - const char16 *p; // Position in source text - const char16 *end; // End of source text; *end is a null character - public: - const String source; // Source text - const String sourceLocation; // Description of location from which the source text came - private: - const uint32 initialLineNum; // One-based number of current line - std::vector linePositions; // Array of line starts recorded by beginLine() - - String *recordString; // String, if any, into which recordChar() records characters; not owned by the Reader - const char16 *recordBase; // Position of last beginRecording() call - const char16 *recordPos; // Position of last recordChar() call; nil if a discrepancy occurred - public: - - Reader(const String &source, const String &sourceLocation, uint32 initialLineNum = 1); - private: - Reader(const Reader&); // No copy constructor - void operator=(const Reader&); // No assignment operator - public: - - char16 get() {ASSERT(p <= end); return *p++;} - char16 peek() {ASSERT(p <= end); return *p;} - void unget(uint32 n = 1) {ASSERT(p >= begin + n); p -= n;} - uint32 getPos() const {return static_cast(p - begin);} - void setPos(uint32 pos) {ASSERT(pos <= getPos()); p = begin + pos;} - - bool eof() const {ASSERT(p <= end); return p == end;} - bool peekEof(char16 ch) const {ASSERT(p <= end && *p == ch); return !ch && p == end;} // Faster version. ch is the result of a peek - bool pastEof() const {return p == end+1;} - bool getEof(char16 ch) const {ASSERT(p[-1] == ch); return !ch && p == end+1;} // Faster version. ch is the result of a get - - void beginLine(); - uint32 posToLineNum(uint32 pos) const; - uint32 getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const; - - void beginRecording(String &recordString); - void recordChar(char16 ch); - String &endRecording(); - - void error(Exception::Kind kind, const String &message, uint32 pos); - }; - - - -// -// Lexer -// - - void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote); - void quoteString(Formatter &f, const String &s, char16 quote); - - - class Token { - public: - enum Kind { // Keep synchronized with kindNames, kindFlags, and tokenBinaryOperatorInfos tables - // Special - end, // End of token stream - - number, // Number - string, // String - unit, // Unit after number - regExp, // Regular expression - - // Punctuators - openParenthesis, // ( - closeParenthesis, // ) - openBracket, // [ - closeBracket, // ] - openBrace, // { - closeBrace, // } - - comma, // , - semicolon, // ; - dot, // . - doubleDot, // .. - tripleDot, // ... - arrow, // -> - colon, // : - doubleColon, // :: - pound, // # - at, // @ - - increment, // ++ - decrement, // -- - - complement, // ~ - logicalNot, // ! - - times, // * - divide, // / - modulo, // % - plus, // + - minus, // - - leftShift, // << - rightShift, // >> - logicalRightShift, // >>> - logicalAnd, // && - logicalXor, // ^^ - logicalOr, // || - bitwiseAnd, // & // These must be at constant offsets from logicalAnd ... logicalOr - bitwiseXor, // ^ - bitwiseOr, // | - - assignment, // = - timesEquals, // *= // These must be at constant offsets from times ... bitwiseOr - divideEquals, // /= - moduloEquals, // %= - plusEquals, // += - minusEquals, // -= - leftShiftEquals, // <<= - rightShiftEquals, // >>= - logicalRightShiftEquals, // >>>= - logicalAndEquals, // &&= - logicalXorEquals, // ^^= - logicalOrEquals, // ||= - bitwiseAndEquals, // &= - bitwiseXorEquals, // ^= - bitwiseOrEquals, // |= - - equal, // == - notEqual, // != - lessThan, // < - lessThanOrEqual, // <= - greaterThan, // > // >, >= must be at constant offsets from <, <= - greaterThanOrEqual, // >= - identical, // === - notIdentical, // !== - - question, // ? - - // Reserved words - Abstract, // abstract - Break, // break - Case, // case - Catch, // catch - Class, // class - Const, // const - Continue, // continue - Debugger, // debugger - Default, // default - Delete, // delete - Do, // do - Else, // else - Enum, // enum - Eval, // eval - Export, // export - Extends, // extends - False, // false - Final, // final - Finally, // finally - For, // for - Function, // function - Goto, // goto - If, // if - Implements, // implements - Import, // import - In, // in - Instanceof, // instanceof - Interface, // interface - Native, // native - New, // new - Null, // null - Package, // package - Private, // private - Protected, // protected - Public, // public - Return, // return - Static, // static - Super, // super - Switch, // switch - Synchronized, // synchronized - This, // this - Throw, // throw - Throws, // throws - Transient, // transient - True, // true - Try, // try - Typeof, // typeof - Var, // var - Volatile, // volatile - While, // while - With, // with - - // Non-reserved words - Attribute, // attribute - Constructor, // constructor - Get, // get - Language, // language - Namespace, // namespace - Set, // set - Use, // use - Operator, // operator - - identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code) - - kindsEnd, // End of token kinds - keywordsBegin = Abstract, // Beginning of range of special identifier tokens - keywordsEnd = identifier, // End of range of special identifier tokens - nonreservedBegin = Attribute,// Beginning of range of non-reserved words - nonreservedEnd = identifier,// End of range of non-reserved words - kindsWithCharsBegin = number,// Beginning of range of tokens for which the chars field (below) is valid - kindsWithCharsEnd = regExp+1// End of range of tokens for which the chars field (below) is valid - }; - -#define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \ - Token::Get: \ - case Token::Set: \ - case Token::identifier: \ - case Token::Operator \ - -#define CASE_TOKEN_NONRESERVED \ - Token::Attribute: \ - case Token::Constructor: \ - case Token::Get: \ - case Token::Language: \ - case Token::Namespace: \ - case Token::Set: \ - case Token::Use: \ - case Token::identifier - - enum Flag { - isAttribute, // True if this token is an attribute - canFollowAttribute, // True if this token is an attribute or can follow an attribute - canFollowReturn, // True if this token can follow a return without an expression - canFollowGet // True if this token can follow a get or set in a FunctionName - }; - - private: - static const char *const kindNames[kindsEnd]; - static const uchar kindFlags[kindsEnd]; - - #ifdef DEBUG - bool valid; // True if this token has been initialized - #endif - Kind kind; // The token's kind - bool lineBreak; // True if line break precedes this token - uint32 pos; // Source position of this token - const StringAtom *id; // The token's characters; non-nil for identifiers, keywords, and regular expressions only - String chars; // The token's characters; valid for strings, units, numbers, and regular expression flags only - float64 value; // The token's value (numbers only) - - #ifdef DEBUG - Token(): valid(false) {} - #endif - - public: - static void initKeywords(World &world); - static bool isSpecialKind(Kind kind) {return kind <= regExp || kind == identifier;} - static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];} - - Kind getKind() const {ASSERT(valid); return kind;} - bool hasKind(Kind k) const {ASSERT(valid); return kind == k;} - bool hasIdentifierKind() const {ASSERT(nonreservedEnd == identifier && kindsEnd == identifier+1); return kind >= nonreservedBegin;} - bool getFlag(Flag f) const {ASSERT(valid); return (kindFlags[kind] & 1<= kindsWithCharsBegin && kind < kindsWithCharsEnd); return chars;} - float64 getValue() const {ASSERT(valid && kind == number); return value;} - - friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} - void print(Formatter &f, bool debug = false) const; - - friend class Lexer; - }; - - - class Lexer { - enum {tokenLookahead = 2}; // Number of tokens that can be simultaneously live - #ifdef DEBUG - enum {tokenGuard = 10}; // Number of invalid tokens added to circular token buffer to catch references to old tokens - #else - enum {tokenGuard = 0}; // Number of invalid tokens added to circular token buffer to catch references to old tokens - #endif - enum {tokenBufferSize = tokenLookahead + tokenGuard}; // Token lookahead buffer size - - Token tokens[tokenBufferSize]; // Circular buffer of recently read or lookahead tokens - Token *nextToken; // Address of next Token in the circular buffer to be returned by get() - int nTokensFwd; // Net number of Tokens on which unget() has been called; these Tokens are ahead of nextToken - #ifdef DEBUG - int nTokensBack; // Number of Tokens on which unget() can be called; these Tokens are beind nextToken - bool savedPreferRegExp[tokenBufferSize]; // Circular buffer of saved values of preferRegExp to get() calls - #endif - bool lexingUnit; // True if lexing a unit identifier immediately following a number - public: - World &world; - Reader reader; - - Lexer(World &world, const String &source, const String &sourceLocation, uint32 initialLineNum = 1); - - const Token &get(bool preferRegExp); - const Token *eat(bool preferRegExp, Token::Kind kind); - const Token &peek(bool preferRegExp); - void redesignate(bool preferRegExp); - void unget(); - uint32 getPos() const; - - private: - void syntaxError(const char *message, uint backUp = 1); - char16 getChar(); - char16 internalGetChar(char16 ch); - char16 peekChar(); - char16 internalPeekChar(char16 ch); - bool testChar(char16 ch); - - char16 lexEscape(bool unicodeOnly); - bool lexIdentifier(String &s, bool allowLeadingDigit); - bool lexNumeral(); - void lexString(String &s, char16 separator); - void lexRegExp(); - void lexToken(bool preferRegExp); - }; - - #ifndef DEBUG - inline void Lexer::redesignate(bool) {} // See description for the DEBUG version inside parser.cpp - #endif - - // Return the position of the first character of the next token, which must have been peeked. - inline uint32 Lexer::getPos() const - { - ASSERT(nTokensFwd); - return nextToken->getPos(); - } - - // // Language Selectors // - class Language { - enum { - minorVersion = 0, // Single BCD digit representing the minor JavaScript version - minorVersionBits = 4, - majorVersion = 4, // Single BCD digit representing the major JavaScript version - majorVersionBits = 4, - strictSemantics = 8, // True when strict semantics are in use - strictSyntax = 9, // True when strict syntax is in use - unknown = 31 // True when language is unknown - }; - uint32 flags; // Bitmap of flags at locations as above - }; + class Language { + enum { + minorVersion = 0, // Single BCD digit representing the minor + // JavaScript version + minorVersionBits = 4, + majorVersion = 4, // Single BCD digit representing the major + // JavaScript version + majorVersionBits = 4, + strictSemantics = 8, // True when strict semantics are in use + strictSyntax = 9, // True when strict syntax is in use + unknown = 31 // True when language is unknown + }; + uint32 flags; // Bitmap of flags at locations as above + }; // // Parser // +// The structures below are generally allocated inside an arena. The +// structures' destructors may never be called, so these structures should not +// hold onto any data that needs to be destroyed explicitly. Strings are +// allocated via newArenaString. - // The structures below are generally allocated inside an arena. The structures' destructors - // may never be called, so these structures should not hold onto any data that needs to be - // destroyed explicitly. Strings are allocated via newArenaString. + struct ParseNode: ArenaObject { + uint32 pos; // Position of this statement or expression + + explicit ParseNode(uint32 pos): pos(pos) {} + }; - struct ParseNode: ArenaObject { - uint32 pos; // Position of this statement or expression - - explicit ParseNode(uint32 pos): pos(pos) {} - }; +// A helper template for creating linked lists of ParseNode subtypes. N should +// be derived from a ParseNode and should have an instance variable called +// of type N* and that is initialized to nil when an N instance is +// created. + template + class NodeQueue { + public: + N *first; // Head of queue + private: + N **last; // Next link of last element of queue + + public: + NodeQueue(): first(0), last(&first) {} + private: + NodeQueue(const NodeQueue&); // No copy constructor + void operator=(const NodeQueue&); // No assignment operator + public: + void operator+=(N *elt) { + ASSERT(elt && !elt->next); *last = elt; last = &elt->next; + } + }; - // A helper template for creating linked lists of ParseNode subtypes. N should be derived - // from a ParseNode and should have an instance variable called of type N* and that - // is initialized to nil when an N instance is created. - template - class NodeQueue { - public: - N *first; // Head of queue - private: - N **last; // Next link of last element of queue - - public: - NodeQueue(): first(0), last(&first) {} - private: - NodeQueue(const NodeQueue&); // No copy constructor - void operator=(const NodeQueue&); // No assignment operator - public: - void operator+=(N *elt) {ASSERT(elt && !elt->next); *last = elt; last = &elt->next;} - }; - - - struct ExprNode; - struct AttributeStmtNode; - struct BlockStmtNode; - - + struct ExprNode; + struct AttributeStmtNode; + struct BlockStmtNode; + struct IdentifierList; struct VariableBinding: ParseNode { - VariableBinding *next; // Next binding in a linked list of variable or parameter bindings + VariableBinding *next; // Next binding in a linked list of + // variable or parameter bindings IdentifierList *aliases; - ExprNode *name; // The variable's name; nil if omitted, which currently can only happen for ... parameters - ExprNode *type; // Type expression or nil if not provided - ExprNode *initializer; // Initial value expression or nil if not provided - - VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, ExprNode *initializer=NULL): - ParseNode(pos), next(0), aliases(0), name(name), type(type), initializer(initializer) {} + ExprNode *name; // The variable's name; nil if omitted, + // which currently can only happen + // for ... parameters + ExprNode *type; // Type expression or nil if not + // provided + ExprNode *initializer; // Initial value expression or nil if + // not provided + bool constant; // true for const variables and + // parameters + VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, + ExprNode *initializer, bool constant): + ParseNode(pos), next(0), aliases(0), name(name), type(type), + initializer(initializer) {} + + void print(PrettyPrinter &f, bool printConst) const; + }; - void print(PrettyPrinter &f) const; - }; + struct ExprNode: ParseNode { + // Keep synchronized with kindNames + enum Kind { // Actual class Operands + none, + identifier, // IdentifierExprNode - struct ExprNode: ParseNode { - enum Kind { // Actual class Operands // Keep synchronized with kindNames - none, - identifier, // IdentifierExprNode // Begin of isPostfix() - number, // NumberExprNode - string, // StringExprNode - regExp, // RegExpExprNode // - Null, // ExprNode null - True, // ExprNode true - False, // ExprNode false - This, // ExprNode this - Super, // ExprNode super + // Begin of isPostfix() + + number, // NumberExprNode + string, // StringExprNode + regExp, // RegExpExprNode // + Null, // ExprNode null + True, // ExprNode true + False, // ExprNode false + This, // ExprNode this + Super, // ExprNode super - parentheses, // UnaryExprNode () - numUnit, // NumUnitExprNode "" or - exprUnit, // ExprUnitExprNode () "" - qualify, // BinaryExprNode :: (right-associative: a::b::c represented as a::(b::c)) + parentheses, // UnaryExprNode () + numUnit, // NumUnitExprNode "" or + exprUnit, // ExprUnitExprNode () "" + qualify, // BinaryExprNode :: + // (right-associative: a::b::c represented as + // a::(b::c)) - objectLiteral, // PairListExprNode {:, :, ..., :} - arrayLiteral, // PairListExprNode [, , ..., ] - functionLiteral, // FunctionExprNode function + objectLiteral, // PairListExprNode {:, + // :, ..., :} + arrayLiteral, // PairListExprNode [, , ..., + // ] + functionLiteral, // FunctionExprNode function - call, // InvokeExprNode (:, :, ..., :) - New, // InvokeExprNode new (:, :, ..., :) - index, // InvokeExprNode [:, :, ..., :] + call, // InvokeExprNode (:, + // :, ..., :) + New, // InvokeExprNode new (:, + // :, ..., :) + index, // InvokeExprNode [:, + // :, ..., :] - dot, // BinaryExprNode . // must be identifier or qualify - dotParen, // BinaryExprNode .( ) - at, // BinaryExprNode @ or @( ) - // End of isPostfix() + dot, // BinaryExprNode . + // must be identifier or qualify + dotClass, // UnaryExprNode .class + dotParen, // BinaryExprNode .( ) + at, // BinaryExprNode @ or + // @( ) + + // End of isPostfix() - Delete, // UnaryExprNode delete - Typeof, // UnaryExprNode typeof - Eval, // UnaryExprNode eval - preIncrement, // UnaryExprNode ++ - preDecrement, // UnaryExprNode -- - postIncrement, // UnaryExprNode ++ - postDecrement, // UnaryExprNode -- - plus, // UnaryExprNode + - minus, // UnaryExprNode - - complement, // UnaryExprNode ~ - logicalNot, // UnaryExprNode ! + Delete, // UnaryExprNode delete + Typeof, // UnaryExprNode typeof + Eval, // UnaryExprNode eval + preIncrement, // UnaryExprNode ++ + preDecrement, // UnaryExprNode -- + postIncrement, // UnaryExprNode ++ + postDecrement, // UnaryExprNode -- + plus, // UnaryExprNode + + minus, // UnaryExprNode - + complement, // UnaryExprNode ~ + logicalNot, // UnaryExprNode ! - add, // BinaryExprNode + - subtract, // BinaryExprNode - - multiply, // BinaryExprNode * - divide, // BinaryExprNode / - modulo, // BinaryExprNode % - leftShift, // BinaryExprNode << - rightShift, // BinaryExprNode >> - logicalRightShift, // BinaryExprNode >>> - bitwiseAnd, // BinaryExprNode & - bitwiseXor, // BinaryExprNode ^ - bitwiseOr, // BinaryExprNode | - logicalAnd, // BinaryExprNode && - logicalXor, // BinaryExprNode ^^ - logicalOr, // BinaryExprNode || + add, // BinaryExprNode + + subtract, // BinaryExprNode - + multiply, // BinaryExprNode * + divide, // BinaryExprNode / + modulo, // BinaryExprNode % + leftShift, // BinaryExprNode << + rightShift, // BinaryExprNode >> + logicalRightShift, // BinaryExprNode >>> + bitwiseAnd, // BinaryExprNode & + bitwiseXor, // BinaryExprNode ^ + bitwiseOr, // BinaryExprNode | + logicalAnd, // BinaryExprNode && + logicalXor, // BinaryExprNode ^^ + logicalOr, // BinaryExprNode || - equal, // BinaryExprNode == - notEqual, // BinaryExprNode != - lessThan, // BinaryExprNode < - lessThanOrEqual, // BinaryExprNode <= - greaterThan, // BinaryExprNode > - greaterThanOrEqual, // BinaryExprNode >= - identical, // BinaryExprNode === - notIdentical, // BinaryExprNode !== - In, // BinaryExprNode in - Instanceof, // BinaryExprNode instanceof + equal, // BinaryExprNode == + notEqual, // BinaryExprNode != + lessThan, // BinaryExprNode < + lessThanOrEqual, // BinaryExprNode <= + greaterThan, // BinaryExprNode > + greaterThanOrEqual,// BinaryExprNode >= + identical, // BinaryExprNode === + notIdentical, // BinaryExprNode !== + In, // BinaryExprNode in + Instanceof, // BinaryExprNode instanceof - assignment, // BinaryExprNode = // Begin of isAssigningKind() - addEquals, // BinaryExprNode += - subtractEquals, // BinaryExprNode -= - multiplyEquals, // BinaryExprNode *= - divideEquals, // BinaryExprNode /= - moduloEquals, // BinaryExprNode %= - leftShiftEquals, // BinaryExprNode <<= - rightShiftEquals, // BinaryExprNode >>= - logicalRightShiftEquals, // BinaryExprNode >>>= - bitwiseAndEquals, // BinaryExprNode &= - bitwiseXorEquals, // BinaryExprNode ^= - bitwiseOrEquals, // BinaryExprNode |= - logicalAndEquals, // BinaryExprNode &&= - logicalXorEquals, // BinaryExprNode ^^= - logicalOrEquals, // BinaryExprNode ||= // End of isAssigningKind() + assignment, // BinaryExprNode = + + // Begin of isAssigningKind() + + addEquals, // BinaryExprNode += + subtractEquals, // BinaryExprNode -= + multiplyEquals, // BinaryExprNode *= + divideEquals, // BinaryExprNode /= + moduloEquals, // BinaryExprNode %= + leftShiftEquals, // BinaryExprNode <<= + rightShiftEquals, // BinaryExprNode >>= + logicalRightShiftEquals, // BinaryExprNode >>>= + bitwiseAndEquals, // BinaryExprNode &= + bitwiseXorEquals, // BinaryExprNode ^= + bitwiseOrEquals, // BinaryExprNode |= + logicalAndEquals, // BinaryExprNode &&= + logicalXorEquals, // BinaryExprNode ^^= + logicalOrEquals, // BinaryExprNode ||= - conditional, // TernaryExprNode ? : - comma, // BinaryExprNode , // Comma expressions only - - kindsEnd - }; - - private: - Kind kind; // The node's kind - static const char *const kindNames[kindsEnd]; - public: + // End of isAssigningKind() - ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} + conditional, // TernaryExprNode ? : + comma, // BinaryExprNode , + // Comma expressions only + + kindsEnd + }; + + private: + Kind kind; // The node's kind + static const char *const kindNames[kindsEnd]; + public: - Kind getKind() const {return kind;} - bool hasKind(Kind k) const {return kind == k;} + ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} - static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualify;} - static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;} - static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];} - bool isPostfix() const {return kind >= identifier && kind <= at;} + Kind getKind() const {return kind;} + bool hasKind(Kind k) const {return kind == k;} - virtual void print(PrettyPrinter &f) const; - friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} - }; + static bool isFieldKind(Kind kind) { + return kind == identifier || + kind == number || kind == string || kind == qualify; + } + static bool isAssigningKind(Kind kind) { + return kind >= assignment && kind <= logicalOrEquals; + } + static const char *kindName(Kind kind) { + ASSERT(uint(kind) < kindsEnd); + return kindNames[kind]; + } + bool isPostfix() const {return kind >= identifier && kind <= at;} - // Print e onto f. - inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) {ASSERT(e); e->print(f); return f;} + virtual void print(PrettyPrinter &f) const; + friend Formatter &operator<<(Formatter &f, Kind k) { + f << kindName(k); + return f; + } + }; - struct FunctionName { - enum Prefix { - normal, // No prefix - Get, // get - Set, // set - Operator // operator - }; - - Prefix prefix; // The name's prefix, if any + // Print e onto f. + inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) { + ASSERT(e); e->print(f); return f; + } + + struct FunctionName { + enum Prefix { + normal, // No prefix + Get, // get + Set // set + }; + + Prefix prefix; // The name's prefix, if any ExprNode::Kind op; // The operator, if appropriate - ExprNode *name; // The name; nil if omitted - - FunctionName(): prefix(normal), name(0) {} + ExprNode *name; // The name; nil if omitted + + FunctionName(): prefix(normal), name(0) {} + + void print(PrettyPrinter &f) const; + }; - void print(PrettyPrinter &f) const; - }; - struct FunctionDefinition: FunctionName { - VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any - VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none - VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases. - VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none - ExprNode *resultType; // Result type expression or nil if not provided - BlockStmtNode *body; // Body; nil if none + struct FunctionDefinition: FunctionName { + VariableBinding *parameters; // Linked list of all parameters, + // including optional and rest + // parameters, if any + VariableBinding *optParameters; // Pointer to first non-required + // parameter inside parameters list; + // nil if none + VariableBinding *namedParameters; // The first parameter after the + // named parameter marker. May or may + // not have aliases. + VariableBinding *restParameter; // Pointer to rest parameter inside + // parameters list; nil if none + ExprNode *resultType; // Result type expression or nil if not + // provided + BlockStmtNode *body; // Body; nil if none - void print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const; - }; + void print(PrettyPrinter &f, const AttributeStmtNode *attributes, + bool noSemi) const; + }; - struct IdentifierExprNode: ExprNode { - const StringAtom &name; // The identifier + struct IdentifierExprNode: ExprNode { + const StringAtom &name; // The identifier - IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name): ExprNode(pos, kind), name(name) {} - explicit IdentifierExprNode(const Token &t): ExprNode(t.getPos(), identifier), name(t.getIdentifier()) {} + IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name) : + ExprNode(pos, kind), name(name) {} + explicit IdentifierExprNode(const Token &t) : + ExprNode(t.getPos(), identifier), name(t.getIdentifier()) {} - void print(PrettyPrinter &f) const; - }; - - struct NumberExprNode: ExprNode { - float64 value; // The number's value + void print(PrettyPrinter &f) const; + }; + + struct NumberExprNode: ExprNode { + float64 value; // The number's value - NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {} - explicit NumberExprNode(const Token &t): ExprNode(t.getPos(), number), value(t.getValue()) {} + NumberExprNode(uint32 pos, float64 value) : + ExprNode(pos, number), value(value) {} + explicit NumberExprNode(const Token &t) : + ExprNode(t.getPos(), number), value(t.getValue()) {} - void print(PrettyPrinter &f) const; - }; - - struct StringExprNode: ExprNode { - String &str; // The string + void print(PrettyPrinter &f) const; + }; + + struct StringExprNode: ExprNode { + String &str; // The string - StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {} + StringExprNode(uint32 pos, Kind kind, String &str) : + ExprNode(pos, kind), str(str) {} - void print(PrettyPrinter &f) const; - }; - - struct RegExpExprNode: ExprNode { - const StringAtom &re; // The regular expression's contents - String &flags; // The regular expression's flags + void print(PrettyPrinter &f) const; + }; + + struct RegExpExprNode: ExprNode { + const StringAtom &re; // The regular expression's contents + String &flags; // The regular expression's flags - RegExpExprNode(uint32 pos, Kind kind, const StringAtom &re, String &flags): - ExprNode(pos, kind), re(re), flags(flags) {} + RegExpExprNode(uint32 pos, Kind kind, const StringAtom &re, + String &flags) : + ExprNode(pos, kind), re(re), flags(flags) {} - void print(PrettyPrinter &f) const; - }; - - struct NumUnitExprNode: StringExprNode { // str is the unit string - String &numStr; // The number's source string - float64 num; // The number's value + void print(PrettyPrinter &f) const; + }; + + struct NumUnitExprNode: StringExprNode { // str is the unit string + String &numStr; // The number's source string + float64 num; // The number's value - NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr): - StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} + NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, + String &unitStr): + StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} - void print(PrettyPrinter &f) const; - }; - - struct ExprUnitExprNode: StringExprNode { // str is the unit string - ExprNode *op; // The expression to which the unit is applied; non-nil only + void print(PrettyPrinter &f) const; + }; + + struct ExprUnitExprNode: StringExprNode { // str is the unit string + ExprNode *op; // The expression to which the + // unit is applied; non-nil only - ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr): - StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} + ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr) : + StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; - struct FunctionExprNode: ExprNode { - FunctionDefinition function; // Function definition + struct FunctionExprNode: ExprNode { + FunctionDefinition function; // Function definition - explicit FunctionExprNode(uint32 pos): ExprNode(pos, functionLiteral) {} + explicit FunctionExprNode(uint32 pos) : + ExprNode(pos, functionLiteral) {} - void print(PrettyPrinter &f) const; - }; - - struct ExprPairList: ArenaObject { - ExprPairList *next; // Next pair in linked list - ExprNode *field; // Field expression or nil if not provided - ExprNode *value; // Value expression or nil if not provided - - explicit ExprPairList(ExprNode *field = 0, ExprNode *value = 0): next(0), field(field), value(value) {} - }; + void print(PrettyPrinter &f) const; + }; + + struct ExprPairList: ArenaObject { + ExprPairList *next; // Next pair in linked list + ExprNode *field; // Field expression or nil if not + // provided + ExprNode *value; // Value expression or nil if not + // provided + + explicit ExprPairList(ExprNode *field = 0, ExprNode *value = 0) : + next(0), field(field), value(value) {} + }; - struct PairListExprNode: ExprNode { - ExprPairList *pairs; // Linked list of pairs + struct PairListExprNode: ExprNode { + ExprPairList *pairs; // Linked list of pairs - PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {} + PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs) : + ExprNode(pos, kind), pairs(pairs) {} - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; - struct InvokeExprNode: PairListExprNode { - ExprNode *op; // The called function, called constructor, or indexed object; non-nil only + struct InvokeExprNode: PairListExprNode { + ExprNode *op; // The called function, called + // constructor, or indexed object; + // non-nil only - InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): - PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);} + InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): + PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);} - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; - struct UnaryExprNode: ExprNode { - ExprNode *op; // The unary operator's operand; non-nil only + struct UnaryExprNode: ExprNode { + ExprNode *op; // The unary operator's operand; + // non-nil only - UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);} + UnaryExprNode(uint32 pos, Kind kind, ExprNode *op) : + ExprNode(pos, kind), op(op) {ASSERT(op);} - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; - struct BinaryExprNode: ExprNode { - ExprNode *op1; // The binary operator's first operand; non-nil only - ExprNode *op2; // The binary operator's second operand; non-nil only + struct BinaryExprNode: ExprNode { + ExprNode *op1; // The binary operator's first operand; + // non-nil only + ExprNode *op2; // The binary operator's second operand; + // non-nil only - BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2): - ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} + BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2) : + ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; - struct TernaryExprNode: ExprNode { - ExprNode *op1; // The ternary operator's first operand; non-nil only - ExprNode *op2; // The ternary operator's second operand; non-nil only - ExprNode *op3; // The ternary operator's third operand; non-nil only + struct TernaryExprNode: ExprNode { + ExprNode *op1; // The ternary operator's first operand; + // non-nil only + ExprNode *op2; // The ternary operator's second operand; + // non-nil only + ExprNode *op3; // The ternary operator's third operand; + // non-nil only - TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3): - ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);} + TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, + ExprNode *op3) : + ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) { + ASSERT(op1 && op2 && op3); + } - void print(PrettyPrinter &f) const; - }; + void print(PrettyPrinter &f) const; + }; + + struct StmtNode: ParseNode { + enum Kind { // Actual class Operands + empty, // StmtNode ; + expression, // ExprStmtNode ; + block, // BlockStmtNode { } + label, // LabelStmtNode : + If, // UnaryStmtNode if ( ) + IfElse, // BinaryStmtNode if ( ) else + // + Switch, // SwitchStmtNode switch ( ) + While, // UnaryStmtNode while ( ) + DoWhile, // UnaryStmtNode do while ( ) + With, // UnaryStmtNode with ( ) + For, // ForStmtNode for ( ; + // ; ) + ForIn, // ForStmtNode for ( in + // ) + Case, // ExprStmtNode case : or default : + // Only occurs directly inside a Switch + Break, // GoStmtNode break ; or break ; + Continue, // GoStmtNode continue ; or continue ; + Return, // ExprStmtNode return ; or return ; + Throw, // ExprStmtNode throw ; + Try, // TryStmtNode try + Import, // ImportStmtNode import ; + UseImport, // ImportStmtNode use import ; + Use, // UseStmtNode use namespace ; + Export, // ExportStmtNode export + // ; + Const, // VariableStmtNode const + // ; + Var, // VariableStmtNode var ; + Function, // FunctionStmtNode function + // + Class, // ClassStmtNode class + // extends implements + Interface, // ClassStmtNode interface + // extends + Namespace, // NamespaceStmtNode namespace + // extends + Language, // LanguageStmtNode language ; + Package, // PackageStmtNode package + Debugger // ExprStmtNode debugger ; + }; + + private: + Kind kind; // The node's kind + public: + StmtNode *next; // Next statement in a linked list of statements in + // this block + + StmtNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind), next(0) {} + + Kind getKind() const {return kind;} + bool hasKind(Kind k) const {return kind == k;} + + static void printStatements(PrettyPrinter &f, + const StmtNode *statements); + static void printBlockStatements(PrettyPrinter &f, + const StmtNode *statements, bool loose); + static void printSemi(PrettyPrinter &f, bool noSemi); + void printSubstatement(PrettyPrinter &f, bool noSemi, + const char *continuation = 0) const; + virtual void print(PrettyPrinter &f, bool noSemi) const; + }; + struct ExprStmtNode: StmtNode { + ExprNode *expr; // The expression statement's expression. + // May be nil for default: or + // return-with-no-expression statements. - struct StmtNode: ParseNode { - enum Kind { // Actual class Operands - empty, // StmtNode ; - expression, // ExprStmtNode ; - block, // BlockStmtNode { } - label, // LabelStmtNode : - If, // UnaryStmtNode if ( ) - IfElse, // BinaryStmtNode if ( ) else - Switch, // SwitchStmtNode switch ( ) - While, // UnaryStmtNode while ( ) - DoWhile, // UnaryStmtNode do while ( ) - With, // UnaryStmtNode with ( ) - For, // ForStmtNode for ( ; ; ) - ForIn, // ForStmtNode for ( in ) - Case, // ExprStmtNode case : or default : // Only occurs directly inside a Switch - Break, // GoStmtNode break ; or break ; - Continue, // GoStmtNode continue ; or continue ; - Return, // ExprStmtNode return ; or return ; - Throw, // ExprStmtNode throw ; - Try, // TryStmtNode try - Import, // ImportStmtNode import ; - UseImport, // ImportStmtNode use import ; - Use, // UseStmtNode use namespace ; - Export, // ExportStmtNode export ; - Const, // VariableStmtNode const ; - Var, // VariableStmtNode var ; - Function, // FunctionStmtNode function - Constructor, // FunctionStmtNode constructor - Class, // ClassStmtNode class extends implements - Interface, // ClassStmtNode interface extends - Namespace, // NamespaceStmtNode namespace extends - Language, // LanguageStmtNode language ; - Package, // PackageStmtNode package - Debugger // ExprStmtNode debugger ; - }; - - private: - Kind kind; // The node's kind - public: - StmtNode *next; // Next statement in a linked list of statements in this block + ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr) : + StmtNode(pos, kind), expr(expr) {} - StmtNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind), next(0) {} + void print(PrettyPrinter &f, bool noSemi) const; + }; - Kind getKind() const {return kind;} - bool hasKind(Kind k) const {return kind == k;} + struct DebuggerStmtNode: StmtNode { + DebuggerStmtNode(uint32 pos, Kind kind): StmtNode(pos, kind) {} - static void printStatements(PrettyPrinter &f, const StmtNode *statements); - static void printBlockStatements(PrettyPrinter &f, const StmtNode *statements, bool loose); - static void printSemi(PrettyPrinter &f, bool noSemi); - void printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation = 0) const; - virtual void print(PrettyPrinter &f, bool noSemi) const; - }; + void print(PrettyPrinter &f, bool noSemi) const; + }; - - struct ExprStmtNode: StmtNode { - ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements. - - ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct DebuggerStmtNode: StmtNode { - DebuggerStmtNode(uint32 pos, Kind kind): StmtNode(pos, kind) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct IdentifierList: ArenaObject { - IdentifierList *next; // Next identifier in linked list - const StringAtom &name; // The identifier - - explicit IdentifierList(const StringAtom &name): next(0), name(name) {} + struct IdentifierList: ArenaObject { + IdentifierList *next; // Next identifier in linked list + const StringAtom &name; // The identifier + + explicit IdentifierList(const StringAtom &name): next(0), name(name) {} bool contains(Token::Kind kind); - }; - - struct AttributeStmtNode: StmtNode { - IdentifierList *attributes; // Linked list of block or definition's attributes + }; + + struct AttributeStmtNode: StmtNode { + IdentifierList *attributes; // Linked list of block or definition's + // attributes - AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes): StmtNode(pos, kind), attributes(attributes) {} + AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) : + StmtNode(pos, kind), attributes(attributes) {} - void printAttributes(PrettyPrinter &f) const; - }; - - struct BlockStmtNode: AttributeStmtNode { - StmtNode *statements; // Linked list of block's statements + void printAttributes(PrettyPrinter &f) const; + }; + + struct BlockStmtNode: AttributeStmtNode { + StmtNode *statements; // Linked list of block's statements - BlockStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, StmtNode *statements): - AttributeStmtNode(pos, kind, attributes), statements(statements) {} + BlockStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, + StmtNode *statements) : + AttributeStmtNode(pos, kind, attributes), statements(statements) + {} - void print(PrettyPrinter &f, bool noSemi) const; - void printBlock(PrettyPrinter &f, bool loose) const; - }; - - struct LabelStmtNode: StmtNode { - const StringAtom &name; // The label - StmtNode *stmt; // Labeled statement; non-nil only + void print(PrettyPrinter &f, bool noSemi) const; + void printBlock(PrettyPrinter &f, bool loose) const; + }; + + struct LabelStmtNode: StmtNode { + const StringAtom &name; // The label + StmtNode *stmt; // Labeled statement; non-nil only - LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt): - StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);} + LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt) : + StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);} - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct UnaryStmtNode: ExprStmtNode { - StmtNode *stmt; // First substatement; non-nil only + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct UnaryStmtNode: ExprStmtNode { + StmtNode *stmt; // First substatement; non-nil only - UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt): - ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);} + UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt): + ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);} - void print(PrettyPrinter &f, bool noSemi) const; - virtual void printContents(PrettyPrinter &f, bool noSemi) const; - }; - - struct BinaryStmtNode: UnaryStmtNode { - StmtNode *stmt2; // Second substatement; non-nil only + void print(PrettyPrinter &f, bool noSemi) const; + virtual void printContents(PrettyPrinter &f, bool noSemi) const; + }; + + struct BinaryStmtNode: UnaryStmtNode { + StmtNode *stmt2; // Second substatement; non-nil only - BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2): - UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);} + BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, + StmtNode *stmt2) : + UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) { + ASSERT(stmt2); + } - void printContents(PrettyPrinter &f, bool noSemi) const; - }; - - struct ForStmtNode: StmtNode { - StmtNode *initializer; // For: First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const. - // ForIn: Expression or declaration before 'in'; either an expression, or a Var or a Const with exactly one binding. - ExprNode *expr2; // For: Second item in parentheses; nil if not provided - // ForIn: Subexpression after 'in'; non-nil only - ExprNode *expr3; // For: Third item in parentheses; nil if not provided - // ForIn: nil - StmtNode *stmt; // Substatement; non-nil only + void printContents(PrettyPrinter &f, bool noSemi) const; + }; + + struct ForStmtNode: StmtNode { + StmtNode *initializer; // For: First item in parentheses; + // either nil (if not provided), an + // expression, or a Var, or a Const. + // ForIn: Expression or declaration + // before 'in'; either an expression, + // or a Var or a Const with exactly one + // binding. + ExprNode *expr2; // For: Second item in parentheses; nil + // if not provided + // ForIn: Subexpression after 'in'; + // non-nil only + ExprNode *expr3; // For: Third item in parentheses; nil + // if not provided + // ForIn: nil + StmtNode *stmt; // Substatement; non-nil only - ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, ExprNode *expr2, ExprNode *expr3, StmtNode *stmt): - StmtNode(pos, kind), initializer(initializer), expr2(expr2), expr3(expr3), stmt(stmt) {ASSERT(stmt);} + ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, + ExprNode *expr2, ExprNode *expr3, StmtNode *stmt) : + StmtNode(pos, kind), initializer(initializer), expr2(expr2), + expr3(expr3), stmt(stmt) { + ASSERT(stmt); + } - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct SwitchStmtNode: ExprStmtNode { - StmtNode *statements; // Linked list of switch block's statements, which may include Case and Default statements + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct SwitchStmtNode: ExprStmtNode { + StmtNode *statements; // Linked list of switch block's + // statements, which may include Case + // and Default statements - SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements): ExprStmtNode(pos, Switch, expr), statements(statements) {} + SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements) : + ExprStmtNode(pos, Switch, expr), statements(statements) {} - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct GoStmtNode: StmtNode { - const StringAtom *name; // The label; nil if none + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct GoStmtNode: StmtNode { + const StringAtom *name; // The label; nil if none - GoStmtNode(uint32 pos, Kind kind, const StringAtom *name): StmtNode(pos, kind), name(name) {} + GoStmtNode(uint32 pos, Kind kind, const StringAtom *name) : + StmtNode(pos, kind), name(name) {} - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct CatchClause: ParseNode { - CatchClause *next; // Next catch clause in a linked list of catch clauses - const StringAtom &name; // The name of the variable that will hold the exception - ExprNode *type; // Type expression or nil if not provided - StmtNode *stmt; // The catch clause's body; non-nil only + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct CatchClause: ParseNode { + CatchClause *next; // Next catch clause in a linked list of + // catch clauses + const StringAtom &name; // The name of the variable that will + // hold the exception + ExprNode *type; // Type expression or nil if not provided + StmtNode *stmt; // The catch clause's body; non-nil only - CatchClause(uint32 pos, const StringAtom &name, ExprNode *type, StmtNode *stmt): - ParseNode(pos), next(0), name(name), type(type), stmt(stmt) {ASSERT(stmt);} - }; - - struct TryStmtNode: StmtNode { - StmtNode *stmt; // Substatement being tried; usually a block; non-nil only - CatchClause *catches; // Linked list of catch blocks; may be nil - StmtNode *finally; // Finally block or nil if none + CatchClause(uint32 pos, const StringAtom &name, ExprNode *type, + StmtNode *stmt) : + ParseNode(pos), next(0), name(name), type(type), stmt(stmt) { + ASSERT(stmt); + } + }; + + struct TryStmtNode: StmtNode { + StmtNode *stmt; // Substatement being tried; usually a + // block; non-nil only + CatchClause *catches; // Linked list of catch blocks; may be + // nil + StmtNode *finally; // Finally block or nil if none - TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, StmtNode *finally): - StmtNode(pos, Try), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);} + TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, + StmtNode *finally) : + StmtNode(pos, Try), stmt(stmt), catches(catches), + finally(finally) { + ASSERT(stmt); + } - void print(PrettyPrinter &f, bool noSemi) const; - }; + void print(PrettyPrinter &f, bool noSemi) const; + }; - struct PackageName: ArenaObject { // Either idList or str may be null, but not both - IdentifierList *idList; // The package name as an identifier list - String *str; // The package name as a string - - explicit PackageName(IdentifierList *idList): idList(idList), str(0) {ASSERT(idList);} - explicit PackageName(String &str): idList(0), str(&str) {} - }; - - struct ImportBinding: ParseNode { - ImportBinding *next; // Next binding in a linked list of import bindings - const StringAtom *name; // The package variable's name; nil if omitted - PackageName &packageName; // The package's name - - ImportBinding(uint32 pos, const StringAtom *name, PackageName &packageName): - ParseNode(pos), next(0), name(name), packageName(packageName) {} - }; + struct PackageName: ArenaObject { // Either idList or str may be null, but + // not both + IdentifierList *idList; // The package name as an identifier list + String *str; // The package name as a string + + explicit PackageName(IdentifierList *idList): idList(idList), str(0) { + ASSERT(idList); + } + explicit PackageName(String &str): idList(0), str(&str) {} + }; + + struct ImportBinding: ParseNode { + ImportBinding *next; // Next binding in a linked list of + // import bindings + const StringAtom *name; // The package variable's name; nil if + // omitted + PackageName &packageName; // The package's name + + ImportBinding(uint32 pos, const StringAtom *name, + PackageName &packageName): + ParseNode(pos), next(0), name(name), packageName(packageName) {} + }; - struct ImportStmtNode: StmtNode { - ImportBinding *bindings; // Linked list of import bindings + struct ImportStmtNode: StmtNode { + ImportBinding *bindings; // Linked list of import bindings - ImportStmtNode(uint32 pos, Kind kind, ImportBinding *bindings): StmtNode(pos, kind), bindings(bindings) {} - }; + ImportStmtNode(uint32 pos, Kind kind, ImportBinding *bindings) : + StmtNode(pos, kind), bindings(bindings) {} + }; - struct ExprList: ArenaObject { - ExprList *next; // Next expression in linked list - ExprNode *expr; // Attribute expression; non-nil only - - explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);} - - void printCommaList(PrettyPrinter &f) const; - static void printOptionalCommaList(PrettyPrinter &f, const char *name, const ExprList *list); - }; - - struct UseStmtNode: StmtNode { - ExprList *exprs; // Linked list of namespace expressions + struct ExprList: ArenaObject { + ExprList *next; // Next expression in linked list + ExprNode *expr; // Attribute expression; non-nil only + + explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);} + + void printCommaList(PrettyPrinter &f) const; + static void printOptionalCommaList(PrettyPrinter &f, const char *name, + const ExprList *list); + }; + + struct UseStmtNode: StmtNode { + ExprList *exprs; // Linked list of namespace expressions - UseStmtNode(uint32 pos, Kind kind, ExprList *exprs): StmtNode(pos, kind), exprs(exprs) {} - }; - - struct ExportBinding: ParseNode { - ExportBinding *next; // Next binding in a linked list of export bindings - FunctionName name; // The exported variable's name - FunctionName *initializer; // The original variable's name or nil if not provided - - ExportBinding(uint32 pos, FunctionName *initializer): ParseNode(pos), next(0), initializer(initializer) {} - }; - - struct ExportStmtNode: AttributeStmtNode { - ExportBinding *bindings; // Linked list of export bindings + UseStmtNode(uint32 pos, Kind kind, ExprList *exprs) : + StmtNode(pos, kind), exprs(exprs) {} + }; + + struct ExportBinding: ParseNode { + ExportBinding *next; // Next binding in a linked list of + // export bindings + FunctionName name; // The exported variable's name + FunctionName *initializer; // The original variable's name or nil + // if not provided + + ExportBinding(uint32 pos, FunctionName *initializer) : + ParseNode(pos), next(0), initializer(initializer) {} + }; + + struct ExportStmtNode: AttributeStmtNode { + ExportBinding *bindings; // Linked list of export bindings - ExportStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, ExportBinding *bindings): - AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} - }; + ExportStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, + ExportBinding *bindings) : + AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} + }; - struct VariableStmtNode: AttributeStmtNode { - VariableBinding *bindings; // Linked list of variable bindings + struct VariableStmtNode: AttributeStmtNode { + VariableBinding *bindings; // Linked list of variable bindings - VariableStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, VariableBinding *bindings): - AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} + VariableStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, + VariableBinding *bindings): + AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} - void print(PrettyPrinter &f, bool noSemi) const; - }; + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct FunctionStmtNode: AttributeStmtNode { + FunctionDefinition function; // Function definition - struct FunctionStmtNode: AttributeStmtNode { - FunctionDefinition function; // Function definition + FunctionStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) : + AttributeStmtNode(pos, kind, attributes) {} - FunctionStmtNode(uint32 pos, Kind kind, IdentifierList *attributes): AttributeStmtNode(pos, kind, attributes) {} + void print(PrettyPrinter &f, bool noSemi) const; + }; - void print(PrettyPrinter &f, bool noSemi) const; - }; + struct NamespaceStmtNode: AttributeStmtNode { + ExprNode *name; // The namespace's, interfaces, or + // class's name; non-nil only + ExprList *supers; // Linked list of supernamespace or + // superinterface expressions - struct NamespaceStmtNode: AttributeStmtNode { - ExprNode *name; // The namespace's, interfaces, or class's name; non-nil only - ExprList *supers; // Linked list of supernamespace or superinterface expressions + NamespaceStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, + ExprNode *name, ExprList *supers) : + AttributeStmtNode(pos, kind, attributes), name(name), + supers(supers) { + ASSERT(name); + } - NamespaceStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, ExprNode *name, ExprList *supers): - AttributeStmtNode(pos, kind, attributes), name(name), supers(supers) {ASSERT(name);} + void print(PrettyPrinter &f, bool noSemi) const; + }; - void print(PrettyPrinter &f, bool noSemi) const; - }; + struct ClassStmtNode: NamespaceStmtNode { + ExprNode *superclass; // Superclass expression (classes only); + // nil if omitted + BlockStmtNode *body; // The class's body; nil if omitted - struct ClassStmtNode: NamespaceStmtNode { - ExprNode *superclass; // Superclass expression (classes only); nil if omitted - BlockStmtNode *body; // The class's body; nil if omitted + ClassStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, + ExprNode *name, ExprNode *superclass, + ExprList *superinterfaces, BlockStmtNode *body) : + NamespaceStmtNode(pos, kind, attributes, name, superinterfaces), + superclass(superclass), body(body) {} - ClassStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, ExprNode *name, ExprNode *superclass, ExprList *superinterfaces, - BlockStmtNode *body): - NamespaceStmtNode(pos, kind, attributes, name, superinterfaces), superclass(superclass), body(body) {} + void print(PrettyPrinter &f, bool noSemi) const; + }; - void print(PrettyPrinter &f, bool noSemi) const; - }; + struct LanguageStmtNode: StmtNode { + JavaScript::Language language; // The selected language - struct LanguageStmtNode: StmtNode { - JavaScript::Language language; // The selected language + LanguageStmtNode(uint32 pos, Kind kind, JavaScript::Language language): + StmtNode(pos, kind), language(language) {} + }; - LanguageStmtNode(uint32 pos, Kind kind, JavaScript::Language language): - StmtNode(pos, kind), language(language) {} - }; + struct PackageStmtNode: StmtNode { + PackageName &packageName; // The package's name + BlockStmtNode *body; // The package's body; non-nil only - struct PackageStmtNode: StmtNode { - PackageName &packageName; // The package's name - BlockStmtNode *body; // The package's body; non-nil only - - PackageStmtNode(uint32 pos, Kind kind, PackageName &packageName, BlockStmtNode *body): - StmtNode(pos, kind), packageName(packageName), body(body) {ASSERT(body);} - }; + PackageStmtNode(uint32 pos, Kind kind, PackageName &packageName, + BlockStmtNode *body) : + StmtNode(pos, kind), packageName(packageName), body(body) { + ASSERT(body); + } + }; - class Parser { - public: - Lexer lexer; - Arena &arena; - bool lineBreaksSignificant; // If false, line breaks between tokens are treated as though they were spaces instead + class Parser { + public: + Lexer lexer; + Arena &arena; + bool lineBreaksSignificant; // If false, line breaks between tokens + // are treated as though they were + // spaces instead - Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum = 1); - - private: - Reader &getReader() {return lexer.reader;} - World &getWorld() {return lexer.world;} + Parser(World &world, Arena &arena, const String &source, + const String &sourceLocation, uint32 initialLineNum = 1); + + private: + Reader &getReader() {return lexer.reader;} + World &getWorld() {return lexer.world;} - public: - void syntaxError(const char *message, uint backUp = 1); - void syntaxError(const String &message, uint backUp = 1); - const Token &require(bool preferRegExp, Token::Kind kind); - private: - String ©TokenChars(const Token &t); - bool lineBreakBefore(const Token &t) const {return lineBreaksSignificant && t.getLineBreak();} - bool lineBreakBefore() {return lineBreaksSignificant && lexer.peek(true).getLineBreak();} + public: + void syntaxError(const char *message, uint backUp = 1); + void syntaxError(const String &message, uint backUp = 1); + const Token &require(bool preferRegExp, Token::Kind kind); + private: + String ©TokenChars(const Token &t); + bool lineBreakBefore(const Token &t) const { + return lineBreaksSignificant && t.getLineBreak(); + } + bool lineBreakBefore() { + return lineBreaksSignificant && lexer.peek(true).getLineBreak(); + } - ExprNode *makeIdentifierExpression(const Token &t) const; - ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp); - ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp); - ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp); - PairListExprNode *parseArrayLiteral(const Token &initialToken); - PairListExprNode *parseObjectLiteral(const Token &initialToken); - ExprNode *parsePrimaryExpression(); - BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind); - InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind); - ExprNode *parsePostfixExpression(bool newExpression = false); - void ensurePostfix(const ExprNode *e); - ExprNode *parseUnaryExpression(); + ExprNode *makeIdentifierExpression(const Token &t) const; + ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, + bool preferRegExp); + ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, + bool &foundQualifiers, + bool preferRegExp); + ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp); + PairListExprNode *parseArrayLiteral(const Token &initialToken); + PairListExprNode *parseObjectLiteral(const Token &initialToken); + ExprNode *parsePrimaryExpression(); + BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, + ExprNode::Kind kind, + ExprNode::Kind parenKind); + InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, + Token::Kind closingTokenKind, + ExprNode::Kind invokeKind); + ExprNode *parsePostfixExpression(bool newExpression = false); + void ensurePostfix(const ExprNode *e); + ExprNode *parseUnaryExpression(); - enum Precedence { - pNone, // End tag - pExpression, // Expression - pAssignment, // AssignmentExpression - pConditional, // ConditionalExpression - pLogicalOr, // LogicalOrExpression - pLogicalXor, // LogicalXorExpression - pLogicalAnd, // LogicalAndExpression - pBitwiseOr, // BitwiseOrExpression - pBitwiseXor, // BitwiseXorExpression - pBitwiseAnd, // BitwiseAndExpression - pEquality, // EqualityExpression - pRelational, // RelationalExpression - pShift, // ShiftExpression - pAdditive, // AdditiveExpression - pMultiplicative, // MultiplicativeExpression - pUnary, // UnaryExpression - pPostfix // PostfixExpression - }; + enum Precedence { + pNone, // End tag + pExpression, // Expression + pAssignment, // AssignmentExpression + pConditional, // ConditionalExpression + pLogicalOr, // LogicalOrExpression + pLogicalXor, // LogicalXorExpression + pLogicalAnd, // LogicalAndExpression + pBitwiseOr, // BitwiseOrExpression + pBitwiseXor, // BitwiseXorExpression + pBitwiseAnd, // BitwiseAndExpression + pEquality, // EqualityExpression + pRelational, // RelationalExpression + pShift, // ShiftExpression + pAdditive, // AdditiveExpression + pMultiplicative, // MultiplicativeExpression + pUnary, // UnaryExpression + pPostfix // PostfixExpression + }; - struct BinaryOperatorInfo { - ExprNode::Kind kind; // The kind of BinaryExprNode the operator should generate; ExprNode::none if not a binary operator - Precedence precedenceLeft; // Operators in this operator's left subexpression with precedenceLeft or higher are reduced - Precedence precedenceRight; // This operator's precedence - }; - static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd]; - struct StackedSubexpression; + struct BinaryOperatorInfo { + ExprNode::Kind kind; // The kind of BinaryExprNode the + // operator should generate; + // ExprNode::none if not a binary + // operator + Precedence precedenceLeft; // Operators in this operator's left + // subexpression with precedenceLeft or + // higher are reduced + Precedence precedenceRight; // This operator's precedence + }; + + static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd]; + struct StackedSubexpression; - public: - ExprNode *parseExpression(bool noIn, bool noAssignment = false, bool noComma = false); - ExprNode *parseNonAssignmentExpression(bool noIn) {return parseExpression(noIn, true, true);} - ExprNode *parseAssignmentExpression(bool noIn=false) {return parseExpression(noIn, false, true);} - private: - ExprNode *parseParenthesizedExpression(); - ExprNode *parseTypeExpression(bool noIn=false); - const StringAtom &parseTypedIdentifier(ExprNode *&type); - ExprNode *parseTypeBinding(Token::Kind kind, bool noIn); - ExprList *parseTypeListBinding(Token::Kind kind); - VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn); - void parseFunctionName(FunctionName &fn); - void parseFunctionSignature(FunctionDefinition &fd); - - enum SemicolonState {semiNone, semiNoninsertable, semiInsertable}; - enum AttributeStatement {asAny, asBlock, asConstVar}; - StmtNode *parseBlock(bool inSwitch, bool noCloseBrace); - BlockStmtNode *parseBody(SemicolonState *semicolonState); + public: + ExprNode *parseExpression(bool noIn, bool noAssignment = false, + bool noComma = false); + ExprNode *parseNonAssignmentExpression(bool noIn) { + return parseExpression(noIn, true, true); + } + ExprNode *parseAssignmentExpression(bool noIn=false) { + return parseExpression(noIn, false, true); + } + + private: + ExprNode *parseParenthesizedExpression(); + ExprNode *parseTypeExpression(bool noIn=false); + const StringAtom &parseTypedIdentifier(ExprNode *&type); + ExprNode *parseTypeBinding(Token::Kind kind, bool noIn); + ExprList *parseTypeListBinding(Token::Kind kind); + VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn, + bool constant); + void parseFunctionName(FunctionName &fn); + void parseFunctionSignature(FunctionDefinition &fd); + + enum SemicolonState {semiNone, semiNoninsertable, semiInsertable}; + enum AttributeStatement {asAny, asBlock, asConstVar}; + StmtNode *parseBlock(bool inSwitch, bool noCloseBrace); + BlockStmtNode *parseBody(SemicolonState *semicolonState); ExprNode::Kind validateOperatorName(const Token &name); - StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState); - StmtNode *parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState); - StmtNode *parseAnnotatedBlock(); - StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState); - StmtNode *parseTry(uint32 pos); - public: - StmtNode *parseStatement(bool topLevel, bool inSwitch, SemicolonState &semicolonState); - StmtNode *parseStatementAndSemicolon(SemicolonState &semicolonState); - StmtNode *parseProgram() {return parseBlock(false, true);} + StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, + const Token &t, bool noIn, + SemicolonState &semicolonState); + StmtNode *parseAttributesAndStatement(const Token *t, + AttributeStatement as, + SemicolonState &semicolonState); + StmtNode *parseAnnotatedBlock(); + StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState); + StmtNode *parseTry(uint32 pos); + + public: + StmtNode *parseStatement(bool topLevel, bool inSwitch, + SemicolonState &semicolonState); + StmtNode *parseStatementAndSemicolon(SemicolonState &semicolonState); + StmtNode *parseProgram() {return parseBlock(false, true);} + private: bool lookahead(Token::Kind kind,bool preferRegExp=true); - const Token *match(Token::Kind kind,bool preferRegExp=true); + const Token *match(Token::Kind kind, bool preferRegExp=true); ExprNode *parseIdentifier(); ExprPairList *parseLiteralField(); ExprNode *parseFieldName(); ExprPairList *parseArgumentList(NodeQueue &args); ExprPairList *parseArgumentListPrime(NodeQueue &args); ExprPairList *parseNamedArgumentListPrime(NodeQueue &args); - VariableBinding *parseAllParameters(FunctionDefinition &fd,NodeQueue ¶ms); - VariableBinding *parseNamedParameters(FunctionDefinition &fd,NodeQueue ¶ms); + VariableBinding *parseAllParameters(FunctionDefinition &fd, + NodeQueue ¶ms); + VariableBinding *parseNamedParameters(FunctionDefinition &fd, + NodeQueue ¶ms); VariableBinding *parseRestParameter(); VariableBinding *parseParameter(); - VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd,NodeQueue ¶ms); - VariableBinding *parseNamedRestParameters(FunctionDefinition &fd,NodeQueue ¶ms); + VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd, + NodeQueue ¶ms); + VariableBinding *parseNamedRestParameters(FunctionDefinition &fd, + NodeQueue ¶ms); VariableBinding *parseOptionalParameter(); VariableBinding *parseOptionalParameterPrime(VariableBinding* binding); VariableBinding *parseNamedParameter(NodeQueue &aliases); ExprNode *parseResultSignature(); - }; + }; } -#endif +#endif /* parser_h___ */ diff --git a/mozilla/js2/src/reader.cpp b/mozilla/js2/src/reader.cpp new file mode 100644 index 00000000000..d28cbb92077 --- /dev/null +++ b/mozilla/js2/src/reader.cpp @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include + +#include "reader.h" + +namespace JavaScript +{ + +// Create a Reader reading characters from the source string. +// sourceLocation describes the origin of the source and may be used for +// error messages. initialLineNum is the line number of the first line of the +// source string. + Reader::Reader(const String &source, const String &sourceLocation, + uint32 initialLineNum): + source(source + uni::null), sourceLocation(sourceLocation), + initialLineNum(initialLineNum) + { + begin = p = this->source.data(); + end = begin + this->source.size() - 1; +#ifdef DEBUG + recordString = 0; +#endif + beginLine(); + } + +// Mark the beginning of a line. Call this after reading every line break to +// fill out the line start table. + void + Reader::beginLine() + { + ASSERT(p <= end && (!linePositions.size() || p > linePositions.back())); + linePositions.push_back(p); + } + +// Return the number of the line containing the given character position. +// The line starts should have been recorded by calling beginLine. + uint32 + Reader::posToLineNum(uint32 pos) const + { + ASSERT(pos <= getPos()); + std::vector::const_iterator i = + std::upper_bound(linePositions.begin(), linePositions.end(), + begin + pos); + ASSERT(i != linePositions.begin()); + + return static_cast(i-1 - linePositions.begin()) + + initialLineNum; + } + +// Return the character position as well as pointers to the beginning and end +// (not including the line terminator) of the nth line. If lineNum is out of +// range, return 0 and two nulls. The line starts should have been recorded by +// calling beginLine(). If the nth line is the last one recorded, then getLine +// manually finds the line ending by searching for a line break; otherwise, +// getLine assumes that the line ends one character before the beginning +// of the next line. + uint32 + Reader::getLine(uint32 lineNum, const char16 *&lineBegin, + const char16 *&lineEnd) const + { + lineBegin = 0; + lineEnd = 0; + if (lineNum < initialLineNum) + return 0; + lineNum -= initialLineNum; + if (lineNum >= linePositions.size()) + return 0; + lineBegin = linePositions[lineNum]; + + const char16 *e; + ++lineNum; + if (lineNum < linePositions.size()) + e = linePositions[lineNum] - 1; + else { + e = lineBegin; + const char16 *end = Reader::end; + while (e != end && !isLineBreak(*e)) + ++e; + } + lineEnd = e; + return static_cast(lineBegin - begin); + } + +// Begin accumulating characters into the recordString, whose initial value is +// ignored and cleared. Each character passed to recordChar() is added to the +// end of the recordString. Recording ends when endRecord() or beginLine() +// is called. Recording is significantly optimized when the characters passed +// to readChar() are the same characters as read by get(). In this case the +// record String does not get allocated until endRecord() is called or a +// discrepancy appears between get() and recordChar(). + void + Reader::beginRecording(String &recordString) + { + Reader::recordString = &recordString; + recordBase = p; + recordPos = p; + } + +// Append ch to the recordString. + void + Reader::recordChar(char16 ch) + { + ASSERT(recordString); + if (recordPos) { + if (recordPos != end && *recordPos == ch) { + recordPos++; + return; + } else { + recordString->assign(recordBase, recordPos); + recordPos = 0; + } + } + *recordString += ch; + } + +// Finish recording characters into the recordString that was last passed to +// beginRecording(). Return that recordString. + String & + Reader::endRecording() + { + String *rs = recordString; + ASSERT(rs); + if (recordPos) + rs->assign(recordBase, recordPos); + recordString = 0; + return *rs; + } + +// Report an error at the given character position in the source code. + void + Reader::error(Exception::Kind kind, const String &message, uint32 pos) + { + uint32 lineNum = posToLineNum(pos); + const char16 *lineBegin; + const char16 *lineEnd; + uint32 linePos = getLine(lineNum, lineBegin, lineEnd); + ASSERT(lineBegin && lineEnd && linePos <= pos); + + throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, + pos, lineBegin, lineEnd); + } + +// Read a line from the input file, including the trailing line break character. +// Return the total number of characters read, which is str's length. +// Translate and sequences to characters; a sequence +// only counts as one character. + size_t + LineReader::readLine(string &str) + { + int ch; + bool oldCRWasLast = crWasLast; + crWasLast = false; + + str.resize(0); + while ((ch = getc(in)) != EOF) { + if (ch == '\n') { + if (!str.size() && oldCRWasLast) + continue; + str += '\n'; + break; + } + if (ch == '\r') { + crWasLast = true; + str += '\n'; + break; + } + str += static_cast(ch); + } + + return str.size(); + } + + + size_t + LineReader::readLine(String &wstr) + { + string str; + size_t n = readLine(str); + wstr.resize(n); + std::transform(str.begin(), str.end(), wstr.begin(), widen); + return n; + } + +} /* namespace JavaScript */ diff --git a/mozilla/js2/src/reader.h b/mozilla/js2/src/reader.h new file mode 100644 index 00000000000..c76da3705ae --- /dev/null +++ b/mozilla/js2/src/reader.h @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef reader_h___ +#define reader_h___ + +#include +#include + +#include "utilities.h" +#include "exception.h" + +namespace JavaScript { + + // A Reader reads Unicode characters from a source string. + // Calling get() yields all of the characters in sequence. + // One character may be read + // past the end of the source; that character appears as a null. + + class Reader { + const char16 *begin; // Beginning of source text + const char16 *p; // Position in source text + const char16 *end; // End of source text; *end is a null character + public: + const String source; // Source text + const String sourceLocation; // Description of location from which + // the source text came + private: + const uint32 initialLineNum; // One-based number of current line + std::vector linePositions; // Array of line starts + // recorded by beginLine() + + String *recordString; // String, if any, into which recordChar() + // records characters; not owned by the Reader + const char16 *recordBase; // Position of last beginRecording() call + const char16 *recordPos; // Position of last recordChar() call; + // nil if a discrepancy occurred + public: + Reader(const String &source, const String &sourceLocation, + uint32 initialLineNum = 1); + private: + Reader(const Reader&); // No copy constructor + void operator=(const Reader&);// No assignment operator + public: + + char16 get() {ASSERT(p <= end);return *p++;} + char16 peek() {ASSERT(p <= end); return *p;} + void unget(uint32 n = 1) {ASSERT(p >= begin + n); p -= n;} + uint32 getPos() const {return static_cast(p - begin);} + void setPos(uint32 pos) {ASSERT(pos <= getPos()); p = begin + pos;} + + bool eof() const {ASSERT(p <= end); return p == end;} + bool peekEof(char16 ch) const { + // Faster version. ch is the result of a peek + ASSERT(p <= end && *p == ch); + return !ch && p == end; + } + bool pastEof() const {return p == end+1;} + bool getEof(char16 ch) const { + // Faster version. ch is the result of a get + ASSERT(p[-1] == ch); return !ch && p == end+1; + } + void beginLine(); + uint32 posToLineNum(uint32 pos) const; + uint32 getLine(uint32 lineNum, const char16 *&lineBegin, + const char16 *&lineEnd) const; + void beginRecording(String &recordString); + void recordChar(char16 ch); + String &endRecording(); + + void error(Exception::Kind kind, const String &message, uint32 pos); + }; + + class LineReader { + FILE *in; // File from which currently reading + bool crWasLast; // True if a CR character was the last one read + + public: + explicit LineReader(FILE *in): in(in), crWasLast(false) {} + + size_t readLine(string &str); + size_t readLine(String &wstr); + }; + +} + +#endif /* reader_h___ */ diff --git a/mozilla/js2/src/stlcfg.h b/mozilla/js2/src/stlcfg.h new file mode 100644 index 00000000000..6369140923c --- /dev/null +++ b/mozilla/js2/src/stlcfg.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef stlcfg_h___ +#define stlcfg_h___ + +#include +#include +#include + +#ifndef _WIN32 +// Microsoft Visual C++ 6.0 bug: standard identifiers should be in std namespace + using std::size_t; + using std::ptrdiff_t; + using std::va_list; + using std::strlen; + using std::strcpy; + using std::FILE; + using std::getc; + using std::fgets; + using std::fputc; + using std::fputs; + using std::sprintf; + using std::snprintf; + using std::vsnprintf; + using std::fprintf; +# define STD std +# define STATIC_CONST(type, expr) static const type expr +#else +# define STD + // Microsoft Visual C++ 6.0 bug: these identifiers should not begin with + // underscores +# define snprintf _snprintf +# define vsnprintf _vsnprintf + // Microsoft Visual C++ 6.0 bug: constants not supported +# define STATIC_CONST(type, expr) enum {expr} +#endif + +using std::string; +using std::auto_ptr; + +#ifdef __GNUC__ // why doesn't g++ support iterator? +namespace std { + template + struct iterator { + typedef T value_type; + typedef Distance difference_type; + typedef Pointer pointer; + typedef Reference reference; + typedef Category iterator_category; + }; +}; +#endif + +#endif /* stlcfg_h___ */ diff --git a/mozilla/js2/src/strings.cpp b/mozilla/js2/src/strings.cpp new file mode 100644 index 00000000000..5f7232717be --- /dev/null +++ b/mozilla/js2/src/strings.cpp @@ -0,0 +1,1466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include + +#include "strings.h" + +namespace JavaScript +{ + +// +// Unicode UTF-16 characters and strings +// + +#ifdef _WIN32 // Microsoft VC6 bug: String constructor and append limited to + // char16 iterators +// Return a String containing the characters of the null-terminated C string cstr +// (without the trailing null). + String + widenCString(const char *cstr) + { + size_t len = strlen(cstr); + String s(len, uni::null); + std::transform(cstr, cstr+len, s.begin(), widen); + return s; + } + + +// Widen and append length characters starting at chars to the end of str. + void + appendChars(String &str, const char *chars, size_t length) + { + String::size_type strLen = str.size(); + str.append(length, uni::null); + std::transform(chars, chars+length, str.begin()+strLen, widen); + } + + +// Widen and insert length characters starting at chars into the given position +// of str. + void + insertChars(String &str, String::size_type pos, const char *chars, + size_t length) + { + str.insert(pos, length, uni::null); + std::transform(chars, chars+length, str.begin()+pos, widen); + } +#endif + + +// Widen and insert the null-terminated string cstr into the given position of +// str. + void + insertChars(String &str, String::size_type pos, const char *cstr) + { + insertChars(str, pos, cstr, strlen(cstr)); + } + + +// Widen and append the null-terminated string cstr to the end of str. +// Return str. + String & + operator+=(String &str, const char *cstr) + { + appendChars(str, cstr, strlen(cstr)); + return str; + } + + +// Return the concatenation of str and the null-terminated string cstr. + String + operator+(const String &str, const char *cstr) + { + return str + widenCString(cstr); + } + + +// Return the concatenation of the null-terminated string cstr and str. + String + operator+(const char *cstr, const String &str) + { + String s = widenCString(cstr); + s += str; + return s; + } + + +// From java.lang.Character: +// +// The character properties are currently encoded into 32 bits in the +// following manner: +// +// 10 bits signed offset used for converting case +// 1 bit if 1, adding the signed offset converts the character to +// lowercase +// 1 bit if 1, subtracting the signed offset converts the character to +// uppercase +// 1 bit if 1, character has a titlecase equivalent (possibly itself) +// 3 bits 0 May not be part of an identifier +// 1 Format control +// 2 May start or continue a JS identifier (includes $ and _) +// 3 May continue a JS identifier +// 4 Behaves like a white space character (but not line break) +// 5 Behaves like a line break character +// 2 bits 0 this character has no numeric property +// 1 adding the digit offset to the character code and then +// masking with 0x1F will produce the desired numeric value +// 2 this character has a "strange" numeric value +// 3 a JS supradecimal digit: adding the digit offset to the +// character code, then masking with 0x1F, then adding 10 +// will produce the desired numeric value +// 5 bits digit offset +// 4 bits reserved for future use +// 5 bits character type + + +// The X table has 1024 entries for a total of 1024 bytes. +const uint8 CharInfo::x[] = { + 0, 1, 2, 3, 4, 5, 6, 7, // 0x0000 + 8, 9, 10, 11, 12, 13, 14, 15, // 0x0200 + 16, 17, 18, 19, 20, 21, 22, 23, // 0x0400 + 24, 25, 26, 27, 28, 28, 28, 28, // 0x0600 + 28, 28, 28, 28, 29, 30, 31, 32, // 0x0800 + 33, 34, 35, 36, 37, 38, 39, 40, // 0x0A00 + 41, 42, 43, 44, 45, 46, 28, 28, // 0x0C00 + 47, 48, 49, 50, 51, 52, 53, 28, // 0x0E00 + 28, 28, 54, 55, 56, 57, 58, 59, // 0x1000 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1200 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1400 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1600 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1800 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1A00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x1C00 + 60, 60, 61, 62, 63, 64, 65, 66, // 0x1E00 + 67, 68, 69, 70, 71, 72, 73, 74, // 0x2000 + 75, 75, 75, 76, 77, 78, 28, 28, // 0x2200 + 79, 80, 81, 82, 83, 83, 84, 85, // 0x2400 + 86, 85, 28, 28, 87, 88, 89, 28, // 0x2600 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x2800 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x2A00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x2C00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x2E00 + 90, 91, 92, 93, 94, 56, 95, 28, // 0x3000 + 96, 97, 98, 99, 83, 100, 83, 101, // 0x3200 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3400 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3600 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3800 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3A00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3C00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x3E00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4000 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4200 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4400 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4600 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4800 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4A00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0x4C00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x4E00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5A00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5C00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x5E00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6A00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6C00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x6E00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7A00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7C00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x7E00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8A00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8C00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x8E00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9A00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0x9C00 + 56, 56, 56, 56, 56, 56, 102, 28, // 0x9E00 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xA000 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xA200 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xA400 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xA600 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xA800 + 28, 28, 28, 28, 28, 28, 28, 28, // 0xAA00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xAC00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xAE00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xB000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xB200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xB400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xB600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xB800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xBA00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xBC00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xBE00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xC000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xC200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xC400 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xC600 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xC800 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xCA00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xCC00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xCE00 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xD000 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xD200 + 56, 56, 56, 56, 56, 56, 56, 56, // 0xD400 + 56, 56, 56, 56, 56, 56, 103, 28, // 0xD600 + 104, 104, 104, 104, 104, 104, 104, 104, // 0xD800 + 104, 104, 104, 104, 104, 104, 104, 104, // 0xDA00 + 104, 104, 104, 104, 104, 104, 104, 104, // 0xDC00 + 104, 104, 104, 104, 104, 104, 104, 104, // 0xDE00 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xE000 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xE200 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xE400 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xE600 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xE800 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xEA00 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xEC00 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xEE00 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xF000 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xF200 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xF400 + 105, 105, 105, 105, 105, 105, 105, 105, // 0xF600 + 105, 105, 105, 105, 56, 56, 56, 56, // 0xF800 + 106, 28, 28, 28, 107, 108, 109, 110, // 0xFA00 + 56, 56, 56, 56, 111, 112, 113, 114, // 0xFC00 + 115, 116, 56, 117, 118, 119, 120, 121 // 0xFE00 +}; + + +// The Y table has 7808 entries for a total of 7808 bytes. +const uint8 CharInfo::y[] = { + 0, 0, 0, 0, 0, 0, 0, 0, // 0 + 0, 1, 14, 1, 1, 14, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, // 0 + 2, 3, 3, 3, 4, 3, 3, 3, // 0 + 5, 6, 3, 7, 3, 8, 3, 3, // 0 + 9, 9, 9, 9, 9, 9, 9, 9, // 0 + 9, 9, 3, 3, 7, 7, 7, 3, // 0 + 3, 10, 10, 10, 10, 10, 10, 10, // 1 + 10, 10, 10, 10, 10, 10, 10, 10, // 1 + 10, 10, 10, 10, 10, 10, 10, 10, // 1 + 10, 10, 10, 5, 3, 6, 11, 12, // 1 + 11, 13, 13, 13, 13, 13, 13, 13, // 1 + 13, 13, 13, 13, 13, 13, 13, 13, // 1 + 13, 13, 13, 13, 13, 13, 13, 13, // 1 + 13, 13, 13, 5, 7, 6, 7, 0, // 1 + 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 2, 3, 4, 4, 4, 4, 15, 15, // 2 + 11, 15, 16, 5, 7, 8, 15, 11, // 2 + 15, 7, 17, 17, 11, 16, 15, 3, // 2 + 11, 18, 16, 6, 19, 19, 19, 3, // 2 + 20, 20, 20, 20, 20, 20, 20, 20, // 3 + 20, 20, 20, 20, 20, 20, 20, 20, // 3 + 20, 20, 20, 20, 20, 20, 20, 7, // 3 + 20, 20, 20, 20, 20, 20, 20, 16, // 3 + 21, 21, 21, 21, 21, 21, 21, 21, // 3 + 21, 21, 21, 21, 21, 21, 21, 21, // 3 + 21, 21, 21, 21, 21, 21, 21, 7, // 3 + 21, 21, 21, 21, 21, 21, 21, 22, // 3 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 23, 24, 23, 24, 23, 24, 23, 24, // 4 + 25, 26, 23, 24, 23, 24, 23, 24, // 4 + 16, 23, 24, 23, 24, 23, 24, 23, // 4 + 24, 23, 24, 23, 24, 23, 24, 23, // 5 + 24, 16, 23, 24, 23, 24, 23, 24, // 5 + 23, 24, 23, 24, 23, 24, 23, 24, // 5 + 23, 24, 23, 24, 23, 24, 23, 24, // 5 + 23, 24, 23, 24, 23, 24, 23, 24, // 5 + 23, 24, 23, 24, 23, 24, 23, 24, // 5 + 23, 24, 23, 24, 23, 24, 23, 24, // 5 + 27, 23, 24, 23, 24, 23, 24, 28, // 5 + 16, 29, 23, 24, 23, 24, 30, 23, // 6 + 24, 31, 31, 23, 24, 16, 32, 32, // 6 + 33, 23, 24, 31, 34, 16, 35, 36, // 6 + 23, 24, 16, 16, 35, 37, 16, 38, // 6 + 23, 24, 23, 24, 23, 24, 38, 23, // 6 + 24, 39, 40, 16, 23, 24, 39, 23, // 6 + 24, 41, 41, 23, 24, 23, 24, 42, // 6 + 23, 24, 16, 40, 23, 24, 40, 40, // 6 + 40, 40, 40, 40, 43, 44, 45, 43, // 7 + 44, 45, 43, 44, 45, 23, 24, 23, // 7 + 24, 23, 24, 23, 24, 23, 24, 23, // 7 + 24, 23, 24, 23, 24, 16, 23, 24, // 7 + 23, 24, 23, 24, 23, 24, 23, 24, // 7 + 23, 24, 23, 24, 23, 24, 23, 24, // 7 + 16, 43, 44, 45, 23, 24, 46, 46, // 7 + 46, 46, 23, 24, 23, 24, 23, 24, // 7 + 23, 24, 23, 24, 23, 24, 23, 24, // 8 + 23, 24, 23, 24, 23, 24, 23, 24, // 8 + 23, 24, 23, 24, 23, 24, 23, 24, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 9 + 46, 46, 46, 46, 46, 46, 46, 46, // 9 + 16, 16, 16, 47, 48, 16, 49, 49, // 9 + 50, 50, 16, 51, 16, 16, 16, 16, // 9 + 49, 16, 16, 52, 16, 16, 16, 16, // 9 + 53, 54, 16, 16, 16, 16, 16, 54, // 9 + 16, 16, 55, 16, 16, 16, 16, 16, // 9 + 16, 16, 16, 16, 16, 16, 16, 16, // 9 + 16, 16, 16, 56, 16, 16, 16, 16, // 10 + 56, 16, 57, 57, 16, 16, 16, 16, // 10 + 16, 16, 58, 16, 16, 16, 16, 16, // 10 + 16, 16, 16, 16, 16, 16, 16, 16, // 10 + 16, 16, 16, 16, 16, 16, 16, 16, // 10 + 16, 46, 46, 46, 46, 46, 46, 46, // 10 + 59, 59, 59, 59, 59, 59, 59, 59, // 10 + 59, 11, 11, 59, 59, 59, 59, 59, // 10 + 59, 59, 11, 11, 11, 11, 11, 11, // 11 + 11, 11, 11, 11, 11, 11, 11, 11, // 11 + 59, 59, 11, 11, 11, 11, 11, 11, // 11 + 11, 11, 11, 11, 11, 11, 11, 46, // 11 + 59, 59, 59, 59, 59, 11, 11, 11, // 11 + 11, 11, 46, 46, 46, 46, 46, 46, // 11 + 46, 46, 46, 46, 46, 46, 46, 46, // 11 + 46, 46, 46, 46, 46, 46, 46, 46, // 11 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 60, 60, // 12 + 60, 60, 60, 60, 60, 60, 46, 46, // 13 + 46, 46, 46, 46, 46, 46, 46, 46, // 13 + 46, 46, 46, 46, 46, 46, 46, 46, // 13 + 46, 46, 46, 46, 46, 46, 46, 46, // 13 + 60, 60, 46, 46, 46, 46, 46, 46, // 13 + 46, 46, 46, 46, 46, 46, 46, 46, // 13 + 46, 46, 46, 46, 3, 3, 46, 46, // 13 + 46, 46, 59, 46, 46, 46, 3, 46, // 13 + 46, 46, 46, 46, 11, 11, 61, 3, // 14 + 62, 62, 62, 46, 63, 46, 64, 64, // 14 + 16, 20, 20, 20, 20, 20, 20, 20, // 14 + 20, 20, 20, 20, 20, 20, 20, 20, // 14 + 20, 20, 46, 20, 20, 20, 20, 20, // 14 + 20, 20, 20, 20, 65, 66, 66, 66, // 14 + 16, 21, 21, 21, 21, 21, 21, 21, // 14 + 21, 21, 21, 21, 21, 21, 21, 21, // 14 + 21, 21, 16, 21, 21, 21, 21, 21, // 15 + 21, 21, 21, 21, 67, 68, 68, 46, // 15 + 69, 70, 38, 38, 38, 71, 72, 46, // 15 + 46, 46, 38, 46, 38, 46, 38, 46, // 15 + 38, 46, 23, 24, 23, 24, 23, 24, // 15 + 23, 24, 23, 24, 23, 24, 23, 24, // 15 + 73, 74, 16, 40, 46, 46, 46, 46, // 15 + 46, 46, 46, 46, 46, 46, 46, 46, // 15 + 46, 75, 75, 75, 75, 75, 75, 75, // 16 + 75, 75, 75, 75, 75, 46, 75, 75, // 16 + 20, 20, 20, 20, 20, 20, 20, 20, // 16 + 20, 20, 20, 20, 20, 20, 20, 20, // 16 + 20, 20, 20, 20, 20, 20, 20, 20, // 16 + 20, 20, 20, 20, 20, 20, 20, 20, // 16 + 21, 21, 21, 21, 21, 21, 21, 21, // 16 + 21, 21, 21, 21, 21, 21, 21, 21, // 16 + 21, 21, 21, 21, 21, 21, 21, 21, // 17 + 21, 21, 21, 21, 21, 21, 21, 21, // 17 + 46, 74, 74, 74, 74, 74, 74, 74, // 17 + 74, 74, 74, 74, 74, 46, 74, 74, // 17 + 23, 24, 23, 24, 23, 24, 23, 24, // 17 + 23, 24, 23, 24, 23, 24, 23, 24, // 17 + 23, 24, 23, 24, 23, 24, 23, 24, // 17 + 23, 24, 23, 24, 23, 24, 23, 24, // 17 + 23, 24, 15, 60, 60, 60, 60, 46, // 18 + 46, 46, 46, 46, 46, 46, 46, 46, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 23, 24, 23, 24, 23, 24, 23, 24, // 18 + 40, 23, 24, 23, 24, 46, 46, 23, // 19 + 24, 46, 46, 23, 24, 46, 46, 46, // 19 + 23, 24, 23, 24, 23, 24, 23, 24, // 19 + 23, 24, 23, 24, 23, 24, 23, 24, // 19 + 23, 24, 23, 24, 23, 24, 23, 24, // 19 + 23, 24, 23, 24, 46, 46, 23, 24, // 19 + 23, 24, 23, 24, 23, 24, 46, 46, // 19 + 23, 24, 46, 46, 46, 46, 46, 46, // 19 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 46, 46, 46, 46, 46, 46, 46, // 20 + 46, 76, 76, 76, 76, 76, 76, 76, // 20 + 76, 76, 76, 76, 76, 76, 76, 76, // 20 + 76, 76, 76, 76, 76, 76, 76, 76, // 21 + 76, 76, 76, 76, 76, 76, 76, 76, // 21 + 76, 76, 76, 76, 76, 76, 76, 46, // 21 + 46, 59, 3, 3, 3, 3, 3, 3, // 21 + 46, 77, 77, 77, 77, 77, 77, 77, // 21 + 77, 77, 77, 77, 77, 77, 77, 77, // 21 + 77, 77, 77, 77, 77, 77, 77, 77, // 21 + 77, 77, 77, 77, 77, 77, 77, 77, // 21 + 77, 77, 77, 77, 77, 77, 77, 16, // 22 + 46, 3, 46, 46, 46, 46, 46, 46, // 22 + 46, 60, 60, 60, 60, 60, 60, 60, // 22 + 60, 60, 60, 60, 60, 60, 60, 60, // 22 + 60, 60, 46, 60, 60, 60, 60, 60, // 22 + 60, 60, 60, 60, 60, 60, 60, 60, // 22 + 60, 60, 60, 60, 60, 60, 60, 60, // 22 + 60, 60, 46, 60, 60, 60, 3, 60, // 22 + 3, 60, 60, 3, 60, 46, 46, 46, // 23 + 46, 46, 46, 46, 46, 46, 46, 46, // 23 + 40, 40, 40, 40, 40, 40, 40, 40, // 23 + 40, 40, 40, 40, 40, 40, 40, 40, // 23 + 40, 40, 40, 40, 40, 40, 40, 40, // 23 + 40, 40, 40, 46, 46, 46, 46, 46, // 23 + 40, 40, 40, 3, 3, 46, 46, 46, // 23 + 46, 46, 46, 46, 46, 46, 46, 46, // 23 + 46, 46, 46, 46, 46, 46, 46, 46, // 24 + 46, 46, 46, 46, 3, 46, 46, 46, // 24 + 46, 46, 46, 46, 46, 46, 46, 46, // 24 + 46, 46, 46, 3, 46, 46, 46, 3, // 24 + 46, 40, 40, 40, 40, 40, 40, 40, // 24 + 40, 40, 40, 40, 40, 40, 40, 40, // 24 + 40, 40, 40, 40, 40, 40, 40, 40, // 24 + 40, 40, 40, 46, 46, 46, 46, 46, // 24 + 59, 40, 40, 40, 40, 40, 40, 40, // 25 + 40, 40, 40, 60, 60, 60, 60, 60, // 25 + 60, 60, 60, 46, 46, 46, 46, 46, // 25 + 46, 46, 46, 46, 46, 46, 46, 46, // 25 + 78, 78, 78, 78, 78, 78, 78, 78, // 25 + 78, 78, 3, 3, 3, 3, 46, 46, // 25 + 60, 40, 40, 40, 40, 40, 40, 40, // 25 + 40, 40, 40, 40, 40, 40, 40, 40, // 25 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 26 + 46, 46, 40, 40, 40, 40, 40, 46, // 26 + 40, 40, 40, 40, 40, 40, 40, 40, // 27 + 40, 40, 40, 40, 40, 40, 40, 46, // 27 + 40, 40, 40, 40, 3, 40, 60, 60, // 27 + 60, 60, 60, 60, 60, 79, 79, 60, // 27 + 60, 60, 60, 60, 60, 59, 59, 60, // 27 + 60, 15, 60, 60, 60, 60, 46, 46, // 27 + 9, 9, 9, 9, 9, 9, 9, 9, // 27 + 9, 9, 46, 46, 46, 46, 46, 46, // 27 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 46, 46, 46, 46, 46, 46, 46, // 28 + 46, 60, 60, 80, 46, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 40, 40, 40, 40, 40, 40, // 29 + 40, 40, 46, 46, 60, 40, 80, 80, // 29 + 80, 60, 60, 60, 60, 60, 60, 60, // 30 + 60, 80, 80, 80, 80, 60, 46, 46, // 30 + 15, 60, 60, 60, 60, 46, 46, 46, // 30 + 40, 40, 40, 40, 40, 40, 40, 40, // 30 + 40, 40, 60, 60, 3, 3, 81, 81, // 30 + 81, 81, 81, 81, 81, 81, 81, 81, // 30 + 3, 46, 46, 46, 46, 46, 46, 46, // 30 + 46, 46, 46, 46, 46, 46, 46, 46, // 30 + 46, 60, 80, 80, 46, 40, 40, 40, // 31 + 40, 40, 40, 40, 40, 46, 46, 40, // 31 + 40, 46, 46, 40, 40, 40, 40, 40, // 31 + 40, 40, 40, 40, 40, 40, 40, 40, // 31 + 40, 40, 40, 40, 40, 40, 40, 40, // 31 + 40, 46, 40, 40, 40, 40, 40, 40, // 31 + 40, 46, 40, 46, 46, 46, 40, 40, // 31 + 40, 40, 46, 46, 60, 46, 80, 80, // 31 + 80, 60, 60, 60, 60, 46, 46, 80, // 32 + 80, 46, 46, 80, 80, 60, 46, 46, // 32 + 46, 46, 46, 46, 46, 46, 46, 80, // 32 + 46, 46, 46, 46, 40, 40, 46, 40, // 32 + 40, 40, 60, 60, 46, 46, 81, 81, // 32 + 81, 81, 81, 81, 81, 81, 81, 81, // 32 + 40, 40, 4, 4, 82, 82, 82, 82, // 32 + 19, 83, 15, 46, 46, 46, 46, 46, // 32 + 46, 46, 60, 46, 46, 40, 40, 40, // 33 + 40, 40, 40, 46, 46, 46, 46, 40, // 33 + 40, 46, 46, 40, 40, 40, 40, 40, // 33 + 40, 40, 40, 40, 40, 40, 40, 40, // 33 + 40, 40, 40, 40, 40, 40, 40, 40, // 33 + 40, 46, 40, 40, 40, 40, 40, 40, // 33 + 40, 46, 40, 40, 46, 40, 40, 46, // 33 + 40, 40, 46, 46, 60, 46, 80, 80, // 33 + 80, 60, 60, 46, 46, 46, 46, 60, // 34 + 60, 46, 46, 60, 60, 60, 46, 46, // 34 + 46, 46, 46, 46, 46, 46, 46, 46, // 34 + 46, 40, 40, 40, 40, 46, 40, 46, // 34 + 46, 46, 46, 46, 46, 46, 81, 81, // 34 + 81, 81, 81, 81, 81, 81, 81, 81, // 34 + 60, 60, 40, 40, 40, 46, 46, 46, // 34 + 46, 46, 46, 46, 46, 46, 46, 46, // 34 + 46, 60, 60, 80, 46, 40, 40, 40, // 35 + 40, 40, 40, 40, 46, 40, 46, 40, // 35 + 40, 40, 46, 40, 40, 40, 40, 40, // 35 + 40, 40, 40, 40, 40, 40, 40, 40, // 35 + 40, 40, 40, 40, 40, 40, 40, 40, // 35 + 40, 46, 40, 40, 40, 40, 40, 40, // 35 + 40, 46, 40, 40, 46, 40, 40, 40, // 35 + 40, 40, 46, 46, 60, 40, 80, 80, // 35 + 80, 60, 60, 60, 60, 60, 46, 60, // 36 + 60, 80, 46, 80, 80, 60, 46, 46, // 36 + 15, 46, 46, 46, 46, 46, 46, 46, // 36 + 46, 46, 46, 46, 46, 46, 46, 46, // 36 + 40, 46, 46, 46, 46, 46, 81, 81, // 36 + 81, 81, 81, 81, 81, 81, 81, 81, // 36 + 46, 46, 46, 46, 46, 46, 46, 46, // 36 + 46, 46, 46, 46, 46, 46, 46, 46, // 36 + 46, 60, 80, 80, 46, 40, 40, 40, // 37 + 40, 40, 40, 40, 40, 46, 46, 40, // 37 + 40, 46, 46, 40, 40, 40, 40, 40, // 37 + 40, 40, 40, 40, 40, 40, 40, 40, // 37 + 40, 40, 40, 40, 40, 40, 40, 40, // 37 + 40, 46, 40, 40, 40, 40, 40, 40, // 37 + 40, 46, 40, 40, 46, 46, 40, 40, // 37 + 40, 40, 46, 46, 60, 40, 80, 60, // 37 + 80, 60, 60, 60, 46, 46, 46, 80, // 38 + 80, 46, 46, 80, 80, 60, 46, 46, // 38 + 46, 46, 46, 46, 46, 46, 60, 80, // 38 + 46, 46, 46, 46, 40, 40, 46, 40, // 38 + 40, 40, 46, 46, 46, 46, 81, 81, // 38 + 81, 81, 81, 81, 81, 81, 81, 81, // 38 + 15, 46, 46, 46, 46, 46, 46, 46, // 38 + 46, 46, 46, 46, 46, 46, 46, 46, // 38 + 46, 46, 60, 80, 46, 40, 40, 40, // 39 + 40, 40, 40, 46, 46, 46, 40, 40, // 39 + 40, 46, 40, 40, 40, 40, 46, 46, // 39 + 46, 40, 40, 46, 40, 46, 40, 40, // 39 + 46, 46, 46, 40, 40, 46, 46, 46, // 39 + 40, 40, 40, 46, 46, 46, 40, 40, // 39 + 40, 40, 40, 40, 40, 40, 46, 40, // 39 + 40, 40, 46, 46, 46, 46, 80, 80, // 39 + 60, 80, 80, 46, 46, 46, 80, 80, // 40 + 80, 46, 80, 80, 80, 60, 46, 46, // 40 + 46, 46, 46, 46, 46, 46, 46, 80, // 40 + 46, 46, 46, 46, 46, 46, 46, 46, // 40 + 46, 46, 46, 46, 46, 46, 46, 81, // 40 + 81, 81, 81, 81, 81, 81, 81, 81, // 40 + 84, 19, 19, 46, 46, 46, 46, 46, // 40 + 46, 46, 46, 46, 46, 46, 46, 46, // 40 + 46, 80, 80, 80, 46, 40, 40, 40, // 41 + 40, 40, 40, 40, 40, 46, 40, 40, // 41 + 40, 46, 40, 40, 40, 40, 40, 40, // 41 + 40, 40, 40, 40, 40, 40, 40, 40, // 41 + 40, 40, 40, 40, 40, 40, 40, 40, // 41 + 40, 46, 40, 40, 40, 40, 40, 40, // 41 + 40, 40, 40, 40, 46, 40, 40, 40, // 41 + 40, 40, 46, 46, 46, 46, 60, 60, // 41 + 60, 80, 80, 80, 80, 46, 60, 60, // 42 + 60, 46, 60, 60, 60, 60, 46, 46, // 42 + 46, 46, 46, 46, 46, 60, 60, 46, // 42 + 46, 46, 46, 46, 46, 46, 46, 46, // 42 + 40, 40, 46, 46, 46, 46, 81, 81, // 42 + 81, 81, 81, 81, 81, 81, 81, 81, // 42 + 46, 46, 46, 46, 46, 46, 46, 46, // 42 + 46, 46, 46, 46, 46, 46, 46, 46, // 42 + 46, 46, 80, 80, 46, 40, 40, 40, // 43 + 40, 40, 40, 40, 40, 46, 40, 40, // 43 + 40, 46, 40, 40, 40, 40, 40, 40, // 43 + 40, 40, 40, 40, 40, 40, 40, 40, // 43 + 40, 40, 40, 40, 40, 40, 40, 40, // 43 + 40, 46, 40, 40, 40, 40, 40, 40, // 43 + 40, 40, 40, 40, 46, 40, 40, 40, // 43 + 40, 40, 46, 46, 46, 46, 80, 60, // 43 + 80, 80, 80, 80, 80, 46, 60, 80, // 44 + 80, 46, 80, 80, 60, 60, 46, 46, // 44 + 46, 46, 46, 46, 46, 80, 80, 46, // 44 + 46, 46, 46, 46, 46, 46, 40, 46, // 44 + 40, 40, 46, 46, 46, 46, 81, 81, // 44 + 81, 81, 81, 81, 81, 81, 81, 81, // 44 + 46, 46, 46, 46, 46, 46, 46, 46, // 44 + 46, 46, 46, 46, 46, 46, 46, 46, // 44 + 46, 46, 80, 80, 46, 40, 40, 40, // 45 + 40, 40, 40, 40, 40, 46, 40, 40, // 45 + 40, 46, 40, 40, 40, 40, 40, 40, // 45 + 40, 40, 40, 40, 40, 40, 40, 40, // 45 + 40, 40, 40, 40, 40, 40, 40, 40, // 45 + 40, 46, 40, 40, 40, 40, 40, 40, // 45 + 40, 40, 40, 40, 40, 40, 40, 40, // 45 + 40, 40, 46, 46, 46, 46, 80, 80, // 45 + 80, 60, 60, 60, 46, 46, 80, 80, // 46 + 80, 46, 80, 80, 80, 60, 46, 46, // 46 + 46, 46, 46, 46, 46, 46, 46, 80, // 46 + 46, 46, 46, 46, 46, 46, 46, 46, // 46 + 40, 40, 46, 46, 46, 46, 81, 81, // 46 + 81, 81, 81, 81, 81, 81, 81, 81, // 46 + 46, 46, 46, 46, 46, 46, 46, 46, // 46 + 46, 46, 46, 46, 46, 46, 46, 46, // 46 + 46, 40, 40, 40, 40, 40, 40, 40, // 47 + 40, 40, 40, 40, 40, 40, 40, 40, // 47 + 40, 40, 40, 40, 40, 40, 40, 40, // 47 + 40, 40, 40, 40, 40, 40, 40, 40, // 47 + 40, 40, 40, 40, 40, 40, 40, 40, // 47 + 40, 40, 40, 40, 40, 40, 40, 3, // 47 + 40, 60, 40, 40, 60, 60, 60, 60, // 47 + 60, 60, 60, 46, 46, 46, 46, 4, // 47 + 40, 40, 40, 40, 40, 40, 59, 60, // 48 + 60, 60, 60, 60, 60, 60, 60, 15, // 48 + 9, 9, 9, 9, 9, 9, 9, 9, // 48 + 9, 9, 3, 3, 46, 46, 46, 46, // 48 + 46, 46, 46, 46, 46, 46, 46, 46, // 48 + 46, 46, 46, 46, 46, 46, 46, 46, // 48 + 46, 46, 46, 46, 46, 46, 46, 46, // 48 + 46, 46, 46, 46, 46, 46, 46, 46, // 48 + 46, 40, 40, 46, 40, 46, 46, 40, // 49 + 40, 46, 40, 46, 46, 40, 46, 46, // 49 + 46, 46, 46, 46, 40, 40, 40, 40, // 49 + 46, 40, 40, 40, 40, 40, 40, 40, // 49 + 46, 40, 40, 40, 46, 40, 46, 40, // 49 + 46, 46, 40, 40, 46, 40, 40, 3, // 49 + 40, 60, 40, 40, 60, 60, 60, 60, // 49 + 60, 60, 46, 60, 60, 40, 46, 46, // 49 + 40, 40, 40, 40, 40, 46, 59, 46, // 50 + 60, 60, 60, 60, 60, 60, 46, 46, // 50 + 9, 9, 9, 9, 9, 9, 9, 9, // 50 + 9, 9, 46, 46, 40, 40, 46, 46, // 50 + 46, 46, 46, 46, 46, 46, 46, 46, // 50 + 46, 46, 46, 46, 46, 46, 46, 46, // 50 + 46, 46, 46, 46, 46, 46, 46, 46, // 50 + 46, 46, 46, 46, 46, 46, 46, 46, // 50 + 15, 15, 15, 15, 3, 3, 3, 3, // 51 + 3, 3, 3, 3, 3, 3, 3, 3, // 51 + 3, 3, 3, 15, 15, 15, 15, 15, // 51 + 60, 60, 15, 15, 15, 15, 15, 15, // 51 + 78, 78, 78, 78, 78, 78, 78, 78, // 51 + 78, 78, 85, 85, 85, 85, 85, 85, // 51 + 85, 85, 85, 85, 15, 60, 15, 60, // 51 + 15, 60, 5, 6, 5, 6, 80, 80, // 51 + 40, 40, 40, 40, 40, 40, 40, 40, // 52 + 46, 40, 40, 40, 40, 40, 40, 40, // 52 + 40, 40, 40, 40, 40, 40, 40, 40, // 52 + 40, 40, 40, 40, 40, 40, 40, 40, // 52 + 40, 40, 40, 40, 40, 40, 40, 40, // 52 + 40, 40, 46, 46, 46, 46, 46, 46, // 52 + 46, 60, 60, 60, 60, 60, 60, 60, // 52 + 60, 60, 60, 60, 60, 60, 60, 80, // 52 + 60, 60, 60, 60, 60, 3, 60, 60, // 53 + 60, 60, 60, 60, 46, 46, 46, 46, // 53 + 60, 60, 60, 60, 60, 60, 46, 60, // 53 + 46, 60, 60, 60, 60, 60, 60, 60, // 53 + 60, 60, 60, 60, 60, 60, 60, 60, // 53 + 60, 60, 60, 60, 60, 60, 46, 46, // 53 + 46, 60, 60, 60, 60, 60, 60, 60, // 53 + 46, 60, 46, 46, 46, 46, 46, 46, // 53 + 46, 46, 46, 46, 46, 46, 46, 46, // 54 + 46, 46, 46, 46, 46, 46, 46, 46, // 54 + 46, 46, 46, 46, 46, 46, 46, 46, // 54 + 46, 46, 46, 46, 46, 46, 46, 46, // 54 + 76, 76, 76, 76, 76, 76, 76, 76, // 54 + 76, 76, 76, 76, 76, 76, 76, 76, // 54 + 76, 76, 76, 76, 76, 76, 76, 76, // 54 + 76, 76, 76, 76, 76, 76, 76, 76, // 54 + 76, 76, 76, 76, 76, 76, 46, 46, // 55 + 46, 46, 46, 46, 46, 46, 46, 46, // 55 + 16, 16, 16, 16, 16, 16, 16, 16, // 55 + 16, 16, 16, 16, 16, 16, 16, 16, // 55 + 16, 16, 16, 16, 16, 16, 16, 16, // 55 + 16, 16, 16, 16, 16, 16, 16, 16, // 55 + 16, 16, 16, 16, 16, 16, 16, 46, // 55 + 46, 46, 46, 3, 46, 46, 46, 46, // 55 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 56 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 46, 46, 46, 46, 46, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 57 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 46, 46, 46, 46, 46, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 58 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 40, 40, 40, 40, 40, 40, // 59 + 40, 40, 46, 46, 46, 46, 46, 46, // 59 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 60 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 16, 16, // 61 + 16, 16, 16, 16, 46, 46, 46, 46, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 61 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 23, 24, 23, 24, 23, 24, // 62 + 23, 24, 46, 46, 46, 46, 46, 46, // 62 + 86, 86, 86, 86, 86, 86, 86, 86, // 63 + 87, 87, 87, 87, 87, 87, 87, 87, // 63 + 86, 86, 86, 86, 86, 86, 46, 46, // 63 + 87, 87, 87, 87, 87, 87, 46, 46, // 63 + 86, 86, 86, 86, 86, 86, 86, 86, // 63 + 87, 87, 87, 87, 87, 87, 87, 87, // 63 + 86, 86, 86, 86, 86, 86, 86, 86, // 63 + 87, 87, 87, 87, 87, 87, 87, 87, // 63 + 86, 86, 86, 86, 86, 86, 46, 46, // 64 + 87, 87, 87, 87, 87, 87, 46, 46, // 64 + 16, 86, 16, 86, 16, 86, 16, 86, // 64 + 46, 87, 46, 87, 46, 87, 46, 87, // 64 + 86, 86, 86, 86, 86, 86, 86, 86, // 64 + 87, 87, 87, 87, 87, 87, 87, 87, // 64 + 88, 88, 89, 89, 89, 89, 90, 90, // 64 + 91, 91, 92, 92, 93, 93, 46, 46, // 64 + 86, 86, 86, 86, 86, 86, 86, 86, // 65 + 87, 87, 87, 87, 87, 87, 87, 87, // 65 + 86, 86, 86, 86, 86, 86, 86, 86, // 65 + 87, 87, 87, 87, 87, 87, 87, 87, // 65 + 86, 86, 86, 86, 86, 86, 86, 86, // 65 + 87, 87, 87, 87, 87, 87, 87, 87, // 65 + 86, 86, 16, 94, 16, 46, 16, 16, // 65 + 87, 87, 95, 95, 96, 11, 38, 11, // 65 + 11, 11, 16, 94, 16, 46, 16, 16, // 66 + 97, 97, 97, 97, 96, 11, 11, 11, // 66 + 86, 86, 16, 16, 46, 46, 16, 16, // 66 + 87, 87, 98, 98, 46, 11, 11, 11, // 66 + 86, 86, 16, 16, 16, 99, 16, 16, // 66 + 87, 87, 100, 100, 101, 11, 11, 11, // 66 + 46, 46, 16, 94, 16, 46, 16, 16, // 66 + 102, 102, 103, 103, 96, 11, 11, 46, // 66 + 2, 2, 2, 2, 2, 2, 2, 2, // 67 + 2, 2, 2, 2, 104, 104, 104, 104, // 67 + 8, 8, 8, 8, 8, 8, 3, 3, // 67 + 5, 6, 5, 5, 5, 6, 5, 5, // 67 + 3, 3, 3, 3, 3, 3, 3, 3, // 67 + 105, 106, 104, 104, 104, 104, 104, 46, // 67 + 3, 3, 3, 3, 3, 3, 3, 3, // 67 + 3, 5, 6, 3, 3, 3, 3, 12, // 67 + 12, 3, 3, 3, 7, 5, 6, 46, // 68 + 46, 46, 46, 46, 46, 46, 46, 46, // 68 + 46, 46, 46, 46, 46, 46, 46, 46, // 68 + 46, 46, 46, 46, 46, 46, 46, 46, // 68 + 46, 46, 46, 46, 46, 46, 46, 46, // 68 + 46, 46, 104, 104, 104, 104, 104, 104, // 68 + 17, 46, 46, 46, 17, 17, 17, 17, // 68 + 17, 17, 7, 7, 7, 5, 6, 16, // 68 + 107, 107, 107, 107, 107, 107, 107, 107, // 69 + 107, 107, 7, 7, 7, 5, 6, 46, // 69 + 46, 46, 46, 46, 46, 46, 46, 46, // 69 + 46, 46, 46, 46, 46, 46, 46, 46, // 69 + 4, 4, 4, 4, 4, 4, 4, 4, // 69 + 4, 4, 4, 4, 46, 46, 46, 46, // 69 + 46, 46, 46, 46, 46, 46, 46, 46, // 69 + 46, 46, 46, 46, 46, 46, 46, 46, // 69 + 46, 46, 46, 46, 46, 46, 46, 46, // 70 + 46, 46, 46, 46, 46, 46, 46, 46, // 70 + 60, 60, 60, 60, 60, 60, 60, 60, // 70 + 60, 60, 60, 60, 60, 79, 79, 79, // 70 + 79, 60, 46, 46, 46, 46, 46, 46, // 70 + 46, 46, 46, 46, 46, 46, 46, 46, // 70 + 46, 46, 46, 46, 46, 46, 46, 46, // 70 + 46, 46, 46, 46, 46, 46, 46, 46, // 70 + 15, 15, 38, 15, 15, 15, 15, 38, // 71 + 15, 15, 16, 38, 38, 38, 16, 16, // 71 + 38, 38, 38, 16, 15, 38, 15, 15, // 71 + 38, 38, 38, 38, 38, 38, 15, 15, // 71 + 15, 15, 15, 15, 38, 15, 38, 15, // 71 + 38, 15, 38, 38, 38, 38, 16, 16, // 71 + 38, 38, 15, 38, 16, 40, 40, 40, // 71 + 40, 46, 46, 46, 46, 46, 46, 46, // 71 + 46, 46, 46, 46, 46, 46, 46, 46, // 72 + 46, 46, 46, 46, 46, 46, 46, 46, // 72 + 46, 46, 46, 19, 19, 19, 19, 19, // 72 + 19, 19, 19, 19, 19, 19, 19, 108, // 72 + 109, 109, 109, 109, 109, 109, 109, 109, // 72 + 109, 109, 109, 109, 110, 110, 110, 110, // 72 + 111, 111, 111, 111, 111, 111, 111, 111, // 72 + 111, 111, 111, 111, 112, 112, 112, 112, // 72 + 113, 113, 113, 46, 46, 46, 46, 46, // 73 + 46, 46, 46, 46, 46, 46, 46, 46, // 73 + 7, 7, 7, 7, 7, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 73 + 15, 15, 15, 15, 15, 15, 15, 15, // 74 + 15, 15, 15, 15, 15, 15, 15, 15, // 74 + 15, 15, 7, 15, 7, 15, 15, 15, // 74 + 15, 15, 15, 15, 15, 15, 15, 15, // 74 + 15, 15, 15, 15, 15, 15, 15, 15, // 74 + 15, 15, 15, 46, 46, 46, 46, 46, // 74 + 46, 46, 46, 46, 46, 46, 46, 46, // 74 + 46, 46, 46, 46, 46, 46, 46, 46, // 74 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 75 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 7, 7, 7, 7, 7, 7, // 76 + 7, 7, 46, 46, 46, 46, 46, 46, // 76 + 46, 46, 46, 46, 46, 46, 46, 46, // 76 + 15, 46, 15, 15, 15, 15, 15, 15, // 77 + 7, 7, 7, 7, 15, 15, 15, 15, // 77 + 15, 15, 15, 15, 15, 15, 15, 15, // 77 + 15, 15, 15, 15, 15, 15, 15, 15, // 77 + 7, 7, 15, 15, 15, 15, 15, 15, // 77 + 15, 5, 6, 15, 15, 15, 15, 15, // 77 + 15, 15, 15, 15, 15, 15, 15, 15, // 77 + 15, 15, 15, 15, 15, 15, 15, 15, // 77 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 78 + 15, 15, 15, 46, 46, 46, 46, 46, // 78 + 15, 15, 15, 15, 15, 15, 15, 15, // 79 + 15, 15, 15, 15, 15, 15, 15, 15, // 79 + 15, 15, 15, 15, 15, 15, 15, 15, // 79 + 15, 15, 15, 15, 15, 15, 15, 15, // 79 + 15, 15, 15, 15, 15, 46, 46, 46, // 79 + 46, 46, 46, 46, 46, 46, 46, 46, // 79 + 46, 46, 46, 46, 46, 46, 46, 46, // 79 + 46, 46, 46, 46, 46, 46, 46, 46, // 79 + 15, 15, 15, 15, 15, 15, 15, 15, // 80 + 15, 15, 15, 46, 46, 46, 46, 46, // 80 + 46, 46, 46, 46, 46, 46, 46, 46, // 80 + 46, 46, 46, 46, 46, 46, 46, 46, // 80 + 114, 114, 114, 114, 114, 114, 114, 114, // 80 + 114, 114, 114, 114, 114, 114, 114, 114, // 80 + 114, 114, 114, 114, 82, 82, 82, 82, // 80 + 82, 82, 82, 82, 82, 82, 82, 82, // 80 + 82, 82, 82, 82, 82, 82, 82, 82, // 81 + 115, 115, 115, 115, 115, 115, 115, 115, // 81 + 115, 115, 115, 115, 115, 115, 115, 115, // 81 + 115, 115, 115, 115, 15, 15, 15, 15, // 81 + 15, 15, 15, 15, 15, 15, 15, 15, // 81 + 15, 15, 15, 15, 15, 15, 15, 15, // 81 + 15, 15, 15, 15, 15, 15, 116, 116, // 81 + 116, 116, 116, 116, 116, 116, 116, 116, // 81 + 116, 116, 116, 116, 116, 116, 116, 116, // 82 + 116, 116, 116, 116, 116, 116, 116, 116, // 82 + 117, 117, 117, 117, 117, 117, 117, 117, // 82 + 117, 117, 117, 117, 117, 117, 117, 117, // 82 + 117, 117, 117, 117, 117, 117, 117, 117, // 82 + 117, 117, 118, 46, 46, 46, 46, 46, // 82 + 46, 46, 46, 46, 46, 46, 46, 46, // 82 + 46, 46, 46, 46, 46, 46, 46, 46, // 82 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 83 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 46, 46, // 84 + 46, 46, 46, 46, 46, 46, 46, 46, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 84 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 85 + 46, 46, 46, 46, 46, 46, 46, 46, // 85 + 46, 46, 46, 46, 46, 46, 46, 46, // 85 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 46, 46, 46, 46, // 86 + 46, 46, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 15, 15, 15, 15, 15, 15, 15, 15, // 86 + 46, 15, 15, 15, 15, 46, 15, 15, // 87 + 15, 15, 46, 46, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 87 + 46, 15, 15, 15, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 87 + 15, 15, 15, 15, 15, 15, 15, 15, // 88 + 15, 15, 15, 15, 46, 15, 46, 15, // 88 + 15, 15, 15, 46, 46, 46, 15, 46, // 88 + 15, 15, 15, 15, 15, 15, 15, 46, // 88 + 46, 15, 15, 15, 15, 15, 15, 15, // 88 + 46, 46, 46, 46, 46, 46, 46, 46, // 88 + 46, 46, 46, 46, 46, 46, 119, 119, // 88 + 119, 119, 119, 119, 119, 119, 119, 119, // 88 + 114, 114, 114, 114, 114, 114, 114, 114, // 89 + 114, 114, 83, 83, 83, 83, 83, 83, // 89 + 83, 83, 83, 83, 15, 46, 46, 46, // 89 + 15, 15, 15, 15, 15, 15, 15, 15, // 89 + 15, 15, 15, 15, 15, 15, 15, 15, // 89 + 15, 15, 15, 15, 15, 15, 15, 15, // 89 + 46, 15, 15, 15, 15, 15, 15, 15, // 89 + 15, 15, 15, 15, 15, 15, 15, 46, // 89 + 2, 3, 3, 3, 15, 59, 3, 120, // 90 + 5, 6, 5, 6, 5, 6, 5, 6, // 90 + 5, 6, 15, 15, 5, 6, 5, 6, // 90 + 5, 6, 5, 6, 8, 5, 6, 5, // 90 + 15, 121, 121, 121, 121, 121, 121, 121, // 90 + 121, 121, 60, 60, 60, 60, 60, 60, // 90 + 8, 59, 59, 59, 59, 59, 15, 15, // 90 + 46, 46, 46, 46, 46, 46, 46, 15, // 90 + 46, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 91 + 40, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 46, 46, 46, // 92 + 46, 60, 60, 59, 59, 59, 59, 46, // 92 + 46, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 40, 40, 40, // 92 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 40, 40, 40, 40, 40, // 93 + 40, 40, 40, 3, 59, 59, 59, 46, // 93 + 46, 46, 46, 46, 46, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 46, 46, 46, // 94 + 46, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 94 + 40, 40, 40, 40, 40, 40, 40, 40, // 95 + 40, 40, 40, 40, 40, 40, 40, 46, // 95 + 15, 15, 85, 85, 85, 85, 15, 15, // 95 + 15, 15, 15, 15, 15, 15, 15, 15, // 95 + 46, 46, 46, 46, 46, 46, 46, 46, // 95 + 46, 46, 46, 46, 46, 46, 46, 46, // 95 + 46, 46, 46, 46, 46, 46, 46, 46, // 95 + 46, 46, 46, 46, 46, 46, 46, 46, // 95 + 15, 15, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 15, 46, 46, 46, // 96 + 85, 85, 85, 85, 85, 85, 85, 85, // 96 + 85, 85, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 15, 15, 15, 15, // 96 + 15, 15, 15, 15, 46, 46, 46, 46, // 97 + 46, 46, 46, 46, 46, 46, 46, 46, // 97 + 46, 46, 46, 46, 46, 46, 46, 46, // 97 + 46, 46, 46, 46, 46, 46, 46, 46, // 97 + 15, 15, 15, 15, 15, 15, 15, 15, // 97 + 15, 15, 15, 15, 15, 15, 15, 15, // 97 + 15, 15, 15, 15, 15, 15, 15, 15, // 97 + 15, 15, 15, 15, 46, 46, 46, 15, // 97 + 114, 114, 114, 114, 114, 114, 114, 114, // 98 + 114, 114, 15, 15, 15, 15, 15, 15, // 98 + 15, 15, 15, 15, 15, 15, 15, 15, // 98 + 15, 15, 15, 15, 15, 15, 15, 15, // 98 + 15, 15, 15, 15, 15, 15, 15, 15, // 98 + 15, 15, 15, 15, 15, 15, 15, 15, // 98 + 15, 46, 46, 46, 46, 46, 46, 46, // 98 + 46, 46, 46, 46, 46, 46, 46, 46, // 98 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 46, 46, 46, 46, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 99 + 15, 15, 15, 15, 15, 15, 15, 46, // 99 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 46, // 100 + 46, 46, 46, 15, 15, 15, 15, 15, // 100 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 46, 46, // 101 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 15, 15, // 101 + 15, 15, 15, 15, 15, 15, 15, 46, // 101 + 40, 40, 40, 40, 40, 40, 40, 40, // 102 + 40, 40, 40, 40, 40, 40, 40, 40, // 102 + 40, 40, 40, 40, 40, 40, 40, 40, // 102 + 40, 40, 40, 40, 40, 40, 40, 40, // 102 + 40, 40, 40, 40, 40, 40, 46, 46, // 102 + 46, 46, 46, 46, 46, 46, 46, 46, // 102 + 46, 46, 46, 46, 46, 46, 46, 46, // 102 + 46, 46, 46, 46, 46, 46, 46, 46, // 102 + 40, 40, 40, 40, 40, 40, 40, 40, // 103 + 40, 40, 40, 40, 40, 40, 40, 40, // 103 + 40, 40, 40, 40, 40, 40, 40, 40, // 103 + 40, 40, 40, 40, 40, 40, 40, 40, // 103 + 40, 40, 40, 40, 46, 46, 46, 46, // 103 + 46, 46, 46, 46, 46, 46, 46, 46, // 103 + 46, 46, 46, 46, 46, 46, 46, 46, // 103 + 46, 46, 46, 46, 46, 46, 46, 46, // 103 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 122, 122, 122, 122, 122, 122, 122, 122, // 104 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 123, 123, 123, 123, 123, 123, 123, 123, // 105 + 40, 40, 40, 40, 40, 40, 40, 40, // 106 + 40, 40, 40, 40, 40, 40, 40, 40, // 106 + 40, 40, 40, 40, 40, 40, 40, 40, // 106 + 40, 40, 40, 40, 40, 40, 40, 40, // 106 + 40, 40, 40, 40, 40, 40, 40, 40, // 106 + 40, 40, 40, 40, 40, 40, 46, 46, // 106 + 46, 46, 46, 46, 46, 46, 46, 46, // 106 + 46, 46, 46, 46, 46, 46, 46, 46, // 106 + 16, 16, 16, 16, 16, 16, 16, 46, // 107 + 46, 46, 46, 46, 46, 46, 46, 46, // 107 + 46, 46, 46, 16, 16, 16, 16, 16, // 107 + 46, 46, 46, 46, 46, 46, 60, 40, // 107 + 40, 40, 40, 40, 40, 40, 40, 40, // 107 + 40, 7, 40, 40, 40, 40, 40, 40, // 107 + 40, 40, 40, 40, 40, 40, 40, 46, // 107 + 40, 40, 40, 40, 40, 46, 40, 46, // 107 + 40, 40, 46, 40, 40, 46, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 108 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 40, 40, 40, 40, 40, 40, // 109 + 40, 40, 46, 46, 46, 46, 46, 46, // 109 + 46, 46, 46, 46, 46, 46, 46, 46, // 109 + 46, 46, 46, 46, 46, 46, 46, 46, // 110 + 46, 46, 46, 46, 46, 46, 46, 46, // 110 + 46, 46, 46, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 110 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 40, 40, // 111 + 40, 40, 40, 40, 40, 40, 5, 6, // 111 + 46, 46, 46, 46, 46, 46, 46, 46, // 112 + 46, 46, 46, 46, 46, 46, 46, 46, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 112 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 46, 46, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 113 + 40, 40, 40, 40, 40, 40, 40, 40, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 114 + 40, 40, 40, 40, 40, 40, 40, 40, // 114 + 40, 40, 40, 40, 46, 46, 46, 46, // 114 + 46, 46, 46, 46, 46, 46, 46, 46, // 115 + 46, 46, 46, 46, 46, 46, 46, 46, // 115 + 46, 46, 46, 46, 46, 46, 46, 46, // 115 + 46, 46, 46, 46, 46, 46, 46, 46, // 115 + 60, 60, 60, 60, 46, 46, 46, 46, // 115 + 46, 46, 46, 46, 46, 46, 46, 46, // 115 + 3, 8, 8, 12, 12, 5, 6, 5, // 115 + 6, 5, 6, 5, 6, 5, 6, 5, // 115 + 6, 5, 6, 5, 6, 46, 46, 46, // 116 + 46, 3, 3, 3, 3, 12, 12, 12, // 116 + 3, 3, 3, 46, 3, 3, 3, 3, // 116 + 8, 5, 6, 5, 6, 5, 6, 3, // 116 + 3, 3, 7, 8, 7, 7, 7, 46, // 116 + 3, 4, 3, 3, 46, 46, 46, 46, // 116 + 40, 40, 40, 46, 40, 46, 40, 40, // 116 + 40, 40, 40, 40, 40, 40, 40, 40, // 116 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 40, 40, 40, // 117 + 40, 40, 40, 40, 40, 46, 46, 104, // 117 + 46, 3, 3, 3, 4, 3, 3, 3, // 118 + 5, 6, 3, 7, 3, 8, 3, 3, // 118 + 9, 9, 9, 9, 9, 9, 9, 9, // 118 + 9, 9, 3, 3, 7, 7, 7, 3, // 118 + 3, 10, 10, 10, 10, 10, 10, 10, // 118 + 10, 10, 10, 10, 10, 10, 10, 10, // 118 + 10, 10, 10, 10, 10, 10, 10, 10, // 118 + 10, 10, 10, 5, 3, 6, 11, 12, // 118 + 11, 13, 13, 13, 13, 13, 13, 13, // 119 + 13, 13, 13, 13, 13, 13, 13, 13, // 119 + 13, 13, 13, 13, 13, 13, 13, 13, // 119 + 13, 13, 13, 5, 7, 6, 7, 46, // 119 + 46, 3, 5, 6, 3, 3, 40, 40, // 119 + 40, 40, 40, 40, 40, 40, 40, 40, // 119 + 59, 40, 40, 40, 40, 40, 40, 40, // 119 + 40, 40, 40, 40, 40, 40, 40, 40, // 119 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 59, 59, // 120 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 40, 40, // 120 + 40, 40, 40, 40, 40, 40, 40, 46, // 120 + 46, 46, 40, 40, 40, 40, 40, 40, // 121 + 46, 46, 40, 40, 40, 40, 40, 40, // 121 + 46, 46, 40, 40, 40, 40, 40, 40, // 121 + 46, 46, 40, 40, 40, 46, 46, 46, // 121 + 4, 4, 7, 11, 15, 4, 4, 46, // 121 + 7, 7, 7, 7, 7, 15, 15, 46, // 121 + 46, 46, 46, 46, 46, 46, 46, 46, // 121 + 46, 46, 46, 46, 46, 15, 46, 46 // 121 +}; + + +// The A table has 124 entries for a total of 496 bytes. +const uint32 CharInfo::a[] = { + 0x0000000F, // 0 Cc + 0x0004000F, // 1 Cc, whitespace + 0x0004000C, // 2 Zs, whitespace + 0x00000018, // 3 Po + 0x0002001A, // 4 Sc, currency + 0x00000015, // 5 Ps + 0x00000016, // 6 Pe + 0x00000019, // 7 Sm + 0x00000014, // 8 Pd + 0x00036009, // 9 Nd, identifier part, decimal 16 + 0x0822FE01, // 10 Lu, hasLower (add 32), identifier start, supradecimal 31 + 0x0000001B, // 11 Sk + 0x00020017, // 12 Pc, underscore + 0x0812FE02, // 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 + 0x0005000F, // 14 Cc, break + 0x0000001C, // 15 So + 0x00020002, // 16 Ll, identifier start + 0x0000600B, // 17 No, decimal 16 + 0x0000500B, // 18 No, decimal 8 + 0x0000800B, // 19 No, strange + 0x08220001, // 20 Lu, hasLower (add 32), identifier start + 0x08120002, // 21 Ll, hasUpper (subtract 32), identifier start + 0xE1D20002, // 22 Ll, hasUpper (subtract -121), identifier start + 0x00620001, // 23 Lu, hasLower (add 1), identifier start + 0x00520002, // 24 Ll, hasUpper (subtract 1), identifier start + 0xCE620001, // 25 Lu, hasLower (add -199), identifier start + 0x3A120002, // 26 Ll, hasUpper (subtract 232), identifier start + 0xE1E20001, // 27 Lu, hasLower (add -121), identifier start + 0x4B120002, // 28 Ll, hasUpper (subtract 300), identifier start + 0x34A20001, // 29 Lu, hasLower (add 210), identifier start + 0x33A20001, // 30 Lu, hasLower (add 206), identifier start + 0x33620001, // 31 Lu, hasLower (add 205), identifier start + 0x32A20001, // 32 Lu, hasLower (add 202), identifier start + 0x32E20001, // 33 Lu, hasLower (add 203), identifier start + 0x33E20001, // 34 Lu, hasLower (add 207), identifier start + 0x34E20001, // 35 Lu, hasLower (add 211), identifier start + 0x34620001, // 36 Lu, hasLower (add 209), identifier start + 0x35620001, // 37 Lu, hasLower (add 213), identifier start + 0x00020001, // 38 Lu, identifier start + 0x36A20001, // 39 Lu, hasLower (add 218), identifier start + 0x00020005, // 40 Lo, identifier start + 0x36620001, // 41 Lu, hasLower (add 217), identifier start + 0x36E20001, // 42 Lu, hasLower (add 219), identifier start + 0x00AA0001, // 43 Lu, hasLower (add 2), hasTitle, identifier start + 0x007A0003, // 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start + 0x009A0002, // 45 Ll, hasUpper (subtract 2), hasTitle, identifier start + 0x00000000, // 46 unassigned + 0x34920002, // 47 Ll, hasUpper (subtract 210), identifier start + 0x33920002, // 48 Ll, hasUpper (subtract 206), identifier start + 0x33520002, // 49 Ll, hasUpper (subtract 205), identifier start + 0x32920002, // 50 Ll, hasUpper (subtract 202), identifier start + 0x32D20002, // 51 Ll, hasUpper (subtract 203), identifier start + 0x33D20002, // 52 Ll, hasUpper (subtract 207), identifier start + 0x34520002, // 53 Ll, hasUpper (subtract 209), identifier start + 0x34D20002, // 54 Ll, hasUpper (subtract 211), identifier start + 0x35520002, // 55 Ll, hasUpper (subtract 213), identifier start + 0x36920002, // 56 Ll, hasUpper (subtract 218), identifier start + 0x36520002, // 57 Ll, hasUpper (subtract 217), identifier start + 0x36D20002, // 58 Ll, hasUpper (subtract 219), identifier start + 0x00020004, // 59 Lm, identifier start + 0x00030006, // 60 Mn, identifier part + 0x09A20001, // 61 Lu, hasLower (add 38), identifier start + 0x09620001, // 62 Lu, hasLower (add 37), identifier start + 0x10220001, // 63 Lu, hasLower (add 64), identifier start + 0x0FE20001, // 64 Lu, hasLower (add 63), identifier start + 0x09920002, // 65 Ll, hasUpper (subtract 38), identifier start + 0x09520002, // 66 Ll, hasUpper (subtract 37), identifier start + 0x10120002, // 67 Ll, hasUpper (subtract 64), identifier start + 0x0FD20002, // 68 Ll, hasUpper (subtract 63), identifier start + 0x0F920002, // 69 Ll, hasUpper (subtract 62), identifier start + 0x0E520002, // 70 Ll, hasUpper (subtract 57), identifier start + 0x0BD20002, // 71 Ll, hasUpper (subtract 47), identifier start + 0x0D920002, // 72 Ll, hasUpper (subtract 54), identifier start + 0x15920002, // 73 Ll, hasUpper (subtract 86), identifier start + 0x14120002, // 74 Ll, hasUpper (subtract 80), identifier start + 0x14220001, // 75 Lu, hasLower (add 80), identifier start + 0x0C220001, // 76 Lu, hasLower (add 48), identifier start + 0x0C120002, // 77 Ll, hasUpper (subtract 48), identifier start + 0x00034009, // 78 Nd, identifier part, decimal 0 + 0x00000007, // 79 Me + 0x00030008, // 80 Mc, identifier part + 0x00037409, // 81 Nd, identifier part, decimal 26 + 0x00005A0B, // 82 No, decimal 13 + 0x00006E0B, // 83 No, decimal 23 + 0x0000740B, // 84 No, decimal 26 + 0x0000000B, // 85 No + 0xFE120002, // 86 Ll, hasUpper (subtract -8), identifier start + 0xFE220001, // 87 Lu, hasLower (add -8), identifier start + 0xED920002, // 88 Ll, hasUpper (subtract -74), identifier start + 0xEA920002, // 89 Ll, hasUpper (subtract -86), identifier start + 0xE7120002, // 90 Ll, hasUpper (subtract -100), identifier start + 0xE0120002, // 91 Ll, hasUpper (subtract -128), identifier start + 0xE4120002, // 92 Ll, hasUpper (subtract -112), identifier start + 0xE0920002, // 93 Ll, hasUpper (subtract -126), identifier start + 0xFDD20002, // 94 Ll, hasUpper (subtract -9), identifier start + 0xEDA20001, // 95 Lu, hasLower (add -74), identifier start + 0xFDE20001, // 96 Lu, hasLower (add -9), identifier start + 0xEAA20001, // 97 Lu, hasLower (add -86), identifier start + 0xE7220001, // 98 Lu, hasLower (add -100), identifier start + 0xFE520002, // 99 Ll, hasUpper (subtract -7), identifier start + 0xE4220001, // 100 Lu, hasLower (add -112), identifier start + 0xFE620001, // 101 Lu, hasLower (add -7), identifier start + 0xE0220001, // 102 Lu, hasLower (add -128), identifier start + 0xE0A20001, // 103 Lu, hasLower (add -126), identifier start + 0x00010010, // 104 Cf, ignorable + 0x0005000D, // 105 Zl, break + 0x0005000E, // 106 Zp, break + 0x0000400B, // 107 No, decimal 0 + 0x0000440B, // 108 No, decimal 2 + 0x0422420A, // 109 Nl, hasLower (add 16), identifier start, decimal 1 + 0x0422800A, // 110 Nl, hasLower (add 16), identifier start, strange + 0x0412620A, // 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 + 0x0412800A, // 112 Nl, hasUpper (subtract 16), identifier start, strange + 0x0002800A, // 113 Nl, identifier start, strange + 0x0000420B, // 114 No, decimal 1 + 0x0000720B, // 115 No, decimal 25 + 0x06A0001C, // 116 So, hasLower (add 26) + 0x0690001C, // 117 So, hasUpper (subtract 26) + 0x00006C0B, // 118 No, decimal 22 + 0x0000560B, // 119 No, decimal 11 + 0x0002720A, // 120 Nl, identifier start, decimal 25 + 0x0002400A, // 121 Nl, identifier start, decimal 0 + 0x00000013, // 122 Cs + 0x00000012 // 123 Co +}; + + +// Return c converted to upper case. If c cannot be converted to upper case, +// return c unchanged. + char16 + toUpper(char16 c) + { + CharInfo ci(c); + if (ci.info & 0x00100000) + c = static_cast(static_cast(c) - + (static_cast(ci.info) >> 22)); + return c; + } + + +// Return c converted to lower case. If c cannot be converted to lower case, +// return c unchanged. + char16 + toLower(char16 c) + { + CharInfo ci(c); + if (ci.info & 0x00200000) + c = static_cast(static_cast(c) + + (static_cast(ci.info) >> 22)); + return c; + } + + +// Return true if c is an ASCII hexadecimal digit, in which case store the +// digit's numeric value in d. + bool + isASCIIHexDigit(char16 c, uint &digit) + { + uint cv = c; + + if (cv < '0') + return false; + if (cv <= '9') { + digit = cv - '0'; + return true; + } + cv |= 0x20; + if (cv >= 'a' && cv <= 'f') { + digit = cv - 'a' + 10; + return true; + } + return false; + } + + +// Return str advanced past white space characters, but no further than strEnd. + const char16 * + skipWhiteSpace(const char16 *str, const char16 *strEnd) + { + while (str != strEnd && isSpace(*str)) + str++; + return str; + } + +// Allocate a String in the Arena and register that String so that it is +// deallocated at the same time as the Arena. +// DO NOT CALL DELETE ON THE RESULT! + String & + newArenaString(Arena &arena) + { + String *s = new(arena) String(); + arena.registerDestructor(s); + return *s; + } + + String & + newArenaString(Arena &arena, const String &str) + { + String *s = new(arena) String(str); + arena.registerDestructor(s); + return *s; + } + +} diff --git a/mozilla/js2/src/strings.h b/mozilla/js2/src/strings.h new file mode 100644 index 00000000000..679accf9a06 --- /dev/null +++ b/mozilla/js2/src/strings.h @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifndef strings_h___ +#define strings_h___ + +#include + +#include "utilities.h" +#include "mem.h" + +namespace JavaScript +{ + +// A string of UTF-16 characters. Nulls are allowed just like any other +// character. The string is not null-terminated. +// Use wstring if char16 is wchar_t. Otherwise use basic_string. +// +// Eventually we'll want to use a custom class better suited for JavaScript that +// generates less code bloat and separates the concepts of a fixed, read-only +// string from a mutable buffer that is expanding. For now, though, we use the +// standard basic_string. + typedef std::basic_string String; + typedef String string16; + typedef string16::const_iterator string16_citer; + typedef string string8; + typedef string8::const_iterator string8_citer; + + String &newArenaString(Arena &arena); + String &newArenaString(Arena &arena, const String &str); + +// +// Unicode UTF-16 characters and strings +// + + // Special char16s + namespace uni { + const char16 null = '\0'; + const char16 cr = '\r'; + const char16 lf = '\n'; + const char16 space = ' '; + const char16 ls = 0x2028; + const char16 ps = 0x2029; + } + const uint16 firstFormatChar = 0x200C; // Lowest Unicode Cf character + + inline char16 widen(char ch) { + return static_cast(static_cast(ch)); + } + + // Use char16Value to compare char16's for inequality because an + // implementation may have char16's be either signed or unsigned. + inline uint16 char16Value(char16 ch) {return static_cast(ch);} + + // A type that can hold any char16 plus one special value: ueof. + typedef uint32 char16orEOF; + const char16orEOF char16eof = static_cast(-1); + + // If c is a char16, return it; if c is char16eof, return the character + // \uFFFF. + inline char16 char16orEOFToChar16(char16orEOF c) { + return static_cast(c); + } + +#ifndef _WIN32 + // Return a String containing the characters of the null-terminated C + // string cstr (without the trailing null). + inline String widenCString(const char *cstr) { + size_t len = strlen(cstr); + const uchar *ucstr = reinterpret_cast(cstr); + return String(ucstr, ucstr+len); + } + + // Widen and append length characters starting at chars to the end of str. + inline void appendChars(String &str, const char *chars, size_t length) { + const uchar *uchars = reinterpret_cast(chars); + str.append(uchars, uchars + length); + } + + // Widen and append characters between begin and end to the end of str. + inline void appendChars(String &str, const char *begin, const char *end) { + ASSERT(begin <= end); + str.append(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + // Widen and insert length characters starting at chars into the given + // position of str. + inline void insertChars(String &str, String::size_type pos, + const char *chars, size_t length) { + ASSERT(pos <= str.size()); + const uchar *uchars = reinterpret_cast(chars); + str.insert(str.begin() + pos, uchars, uchars + length); + } +#else + // Microsoft VC6 bug: String constructor and append limited to char16 + // iterators + String widenCString(const char *cstr); + void appendChars(String &str, const char *chars, size_t length); + inline void appendChars(String &str, const char *begin, const char *end) { + ASSERT(begin <= end); + appendChars(str, begin, static_cast(end - begin)); + } + + void insertChars(String &str, String::size_type pos, const char *chars, + size_t length); +#endif + + void insertChars(String &str, String::size_type pos, const char *cstr); + + + String &operator+=(String &str, const char *cstr); + String operator+(const String &str, const char *cstr); + String operator+(const char *cstr, const String &str); + inline String &operator+=(String &str, char c) {return str += widen(c);} + inline void clear(String &s) {s.resize(0);} + + + class CharInfo { + uint32 info; // Word from table a. + + // Unicode character attribute lookup tables + static const uint8 x[]; + static const uint8 y[]; + static const uint32 a[]; + + public: + // Enumerated Unicode general category types + enum Type { + Unassigned = 0, // Cn + UppercaseLetter = 1, // Lu + LowercaseLetter = 2, // Ll + TitlecaseLetter = 3, // Lt + ModifierLetter = 4, // Lm + OtherLetter = 5, // Lo + NonSpacingMark = 6, // Mn + EnclosingMark = 7, // Me + CombiningSpacingMark = 8, // Mc + DecimalDigitNumber = 9, // Nd + LetterNumber = 10, // Nl + OtherNumber = 11, // No + SpaceSeparator = 12, // Zs + LineSeparator = 13, // Zl + ParagraphSeparator = 14, // Zp + Control = 15, // Cc + Format = 16, // Cf + PrivateUse = 18, // Co + Surrogate = 19, // Cs + DashPunctuation = 20, // Pd + StartPunctuation = 21, // Ps + EndPunctuation = 22, // Pe + ConnectorPunctuation = 23, // Pc + OtherPunctuation = 24, // Po + MathSymbol = 25, // Sm + CurrencySymbol = 26, // Sc + ModifierSymbol = 27, // Sk + OtherSymbol = 28 // So + }; + + enum Group { + NonIdGroup, // 0 May not be part of an identifier + FormatGroup, // 1 Format control + IdGroup, // 2 May start or continue a JS identifier + // (includes $ and _) + IdContinueGroup, // 3 May continue a JS identifier + // [(IdContinueGroup & -2) == IdGroup] + WhiteGroup, // 4 White space character (but not line break) + LineBreakGroup // 5 Line break character + // [(LineBreakGroup & -2) == WhiteGroup] + }; + + CharInfo() {} + CharInfo(char16 c) : + info(a[y[x[static_cast(c)>>6]<<6 | c&0x3F]]) {} + CharInfo(const CharInfo &ci): info(ci.info) {} + + friend Type cType(const CharInfo &ci) {return static_cast(ci.info & 0x1F);} + friend Group cGroup(const CharInfo &ci) {return static_cast(ci.info >> 16 & 7);} + + friend bool isAlpha(const CharInfo &ci) + { + return ((1<> cType(ci) & 1) != 0; + } + + friend bool isAlphanumeric(const CharInfo &ci) + { + return ((1<> cType(ci) & 1) != 0; + } + + // Return true if this character can start a JavaScript identifier + friend bool isIdLeading(const CharInfo &ci) {return cGroup(ci) == IdGroup;} + // Return true if this character can continue a JavaScript identifier + friend bool isIdContinuing(const CharInfo &ci) {return (cGroup(ci) & -2) == IdGroup;} + + // Return true if this character is a Unicode decimal digit (Nd) character + friend bool isDecimalDigit(const CharInfo &ci) {return cType(ci) == DecimalDigitNumber;} + // Return true if this character is a Unicode white space or line break character + friend bool isSpace(const CharInfo &ci) {return (cGroup(ci) & -2) == WhiteGroup;} + // Return true if this character is a Unicode line break character (LF, CR, LS, or PS) + friend bool isLineBreak(const CharInfo &ci) {return cGroup(ci) == LineBreakGroup;} + // Return true if this character is a Unicode format control character (Cf) + friend bool isFormat(const CharInfo &ci) {return cGroup(ci) == FormatGroup;} + + friend bool isUpper(const CharInfo &ci) {return cType(ci) == UppercaseLetter;} + friend bool isLower(const CharInfo &ci) {return cType(ci) == LowercaseLetter;} + + friend char16 toUpper(char16 c); + friend char16 toLower(char16 c); + }; + + inline bool isASCIIDecimalDigit(char16 c) {return c >= '0' && c <= '9';} + bool isASCIIHexDigit(char16 c, uint &digit); + + const char16 *skipWhiteSpace(const char16 *str, const char16 *strEnd); + +} + +#endif /* strings_h___ */ diff --git a/mozilla/js2/src/systemtypes.h b/mozilla/js2/src/systemtypes.h index a846f6d95c5..ae33b7a54b3 100644 --- a/mozilla/js2/src/systemtypes.h +++ b/mozilla/js2/src/systemtypes.h @@ -1,21 +1,35 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #ifndef systemtypes_h #define systemtypes_h @@ -82,12 +96,19 @@ typedef float float32; #endif -// basicAlignment is the maximum alignment required by any native type. An object aligned to -// a multiple of basicAlignment can hold any native type. malloc should return a pointer whose -// lgBasicAlignment least significant bits are clear. -// Currently basicAlignment is set to 8 to allow doubles and int64s to have their natural alignment; -// may be customized for individual platforms. +// basicAlignment is the maximum alignment required by any native type. An +// object aligned to a multiple of basicAlignment can hold any native type. +// malloc should return a pointer whose lgBasicAlignment least significant bits +// are clear. Currently basicAlignment is set to 8 to allow doubles and int64s +// to have their natural alignment; may be customized for individual platforms. const uint lgBasicAlignment = 3; const uint basicAlignment = 1u<", // arrow + ":", // colon + "::", // doubleColon + "#", // pound + "@", // at + "++", // increment + "--", // decrement + "~", // complement + "!", // logicalNot + "*", // times + "/", // divide + "%", // modulo + "+", // plus + "-", // minus + "<<", // leftShift + ">>", // rightShift + ">>>", // logicalRightShift + "&&", // logicalAnd + "^^", // logicalXor + "||", // logicalOr + "&", // bitwiseAnd + "^", // bitwiseXor + "|", // bitwiseOr + "=", // assignment + "*=", // timesEquals + "/=", // divideEquals + "%=", // moduloEquals + "+=", // plusEquals + "-=", // minusEquals + "<<=", // leftShiftEquals + ">>=", // rightShiftEquals + ">>>=", // logicalRightShiftEquals + "&&=", // logicalAndEquals + "^^=", // logicalXorEquals + "||=", // logicalOrEquals + "&=", // bitwiseAndEquals + "^=", // bitwiseXorEquals + "|=", // bitwiseOrEquals + "==", // equal + "!=", // notEqual + "<", // lessThan + "<=", // lessThanOrEqual + ">", // greaterThan + ">=", // greaterThanOrEqual + "===", // identical + "!==", // notIdentical + "?", // question + + // Reserved words + "abstract", // Abstract + "break", // Break + "case", // Case + "catch", // Catch + "class", // Class + "const", // Const + "continue", // Continue + "debugger", // Debugger + "default", // Default + "delete", // Delete + "do", // Do + "else", // Else + "enum", // Enum + "export", // Export + "extends", // Extends + "false", // False + "final", // Final + "finally", // Finally + "for", // For + "function", // Function + "goto", // Goto + "if", // If + "implements", // Implements + "import", // Import + "in", // In + "instanceof", // Instanceof + "interface", // Interface + "namespace", // Namespace + "native", // Native + "new", // New + "null", // Null + "package", // Package + "private", // Private + "protected", // Protected + "public", // Public + "return", // Return + "static", // Static + "super", // Super + "switch", // Switch + "synchronized", // Synchronized + "this", // This + "throw", // Throw + "throws", // Throws + "transient", // Transient + "true", // True + "try", // Try + "typeof", // Typeof + "use", // Use + "var", // Var + "void", // Void + "volatile", // Volatile + "while", // While + "with", // With + + // Non-reserved words + "eval", // Eval + "exclude", // Exclude + "get", // Get + "include", // Include + "set" // Set + }; + + const uchar followRet = 1< + colon, // : + doubleColon, // :: + pound, // # + at, // @ + + increment, // ++ + decrement, // -- + + complement, // ~ + logicalNot, // ! + + times, // * + divide, // / + modulo, // % + plus, // + + minus, // - + leftShift, // << + rightShift, // >> + logicalRightShift, // >>> + logicalAnd, // && + logicalXor, // ^^ + logicalOr, // || + bitwiseAnd, // & + + // These must be at constant offsets from logicalAnd ... logicalOr + bitwiseXor, // ^ + bitwiseOr, // | + + assignment, // = + + // These must be at constant offsets from times ... bitwiseOr + timesEquals, // *= + divideEquals, // /= + moduloEquals, // %= + plusEquals, // += + minusEquals, // -= + leftShiftEquals, // <<= + rightShiftEquals, // >>= + logicalRightShiftEquals, // >>>= + logicalAndEquals, // &&= + logicalXorEquals, // ^^= + logicalOrEquals, // ||= + bitwiseAndEquals, // &= + bitwiseXorEquals, // ^= + bitwiseOrEquals, // |= + + equal, // == + notEqual, // != + lessThan, // < + lessThanOrEqual, // <= + greaterThan, // > + + // >, >= must be at constant offsets from <, <= + greaterThanOrEqual, // >= + identical, // === + notIdentical, // !== + + question, // ? + + // Reserved words + Abstract, // abstract + Break, // break + Case, // case + Catch, // catch + Class, // class + Const, // const + Continue, // continue + Debugger, // debugger + Default, // default + Delete, // delete + Do, // do + Else, // else + Enum, // enum + Export, // export + Extends, // extends + False, // false + Final, // final + Finally, // finally + For, // for + Function, // function + Goto, // goto + If, // if + Implements, // implements + Import, // import + In, // in + Instanceof, // instanceof + Interface, // interface + Namespace, // namespace + Native, // native + New, // new + Null, // null + Package, // package + Private, // private + Protected, // protected + Public, // public + Return, // return + Static, // static + Super, // super + Switch, // switch + Synchronized, // synchronized + This, // this + Throw, // throw + Throws, // throws + Transient, // transient + True, // true + Try, // try + Typeof, // typeof + Use, // use + Var, // var + Void, // void + Volatile, // volatile + While, // while + With, // with + + // Non-reserved words + Eval, // eval + Exclude, // exclude + Get, // get + Include, // include + Set, // set + + identifier, // Non-keyword identifier + // (may be same as a keyword if it + // contains an escape code) + kindsEnd, // End of token kinds + + keywordsBegin = Abstract, // Beginning of range of special + // identifier tokens + keywordsEnd = identifier, // End of range of special identifier + // tokens + nonreservedBegin = Eval, // Beginning of range of non-reserved + // words + nonreservedEnd = identifier, // End of range of non-reserved words + kindsWithCharsBegin = number, // Beginning of range of tokens for + // which the chars field (below) is + // valid + kindsWithCharsEnd = regExp+1 // End of range of tokens for which + // the chars field (below) is valid + }; + +#define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \ + Token::Eval: \ + case Token::Exclude: \ + case Token::Get: \ + case Token::Include: \ + case Token::Set: \ + case Token::identifier + +#define CASE_TOKEN_NONRESERVED \ + Token::Eval: \ + case Token::Exclude: \ + case Token::Get: \ + case Token::Include: \ + case Token::Set: \ + case Token::identifier + + enum Flag { + isAttribute, // True if this token is an attribute + canFollowAttribute, // True if this token is an attribute or can + // follow an attribute + canFollowReturn, // True if this token can follow a return + // without an expression + canFollowGet // True if this token can follow a get or + // set in a FunctionName + }; + + private: + static const char *const kindNames[kindsEnd]; + static const uchar kindFlags[kindsEnd]; + +#ifdef DEBUG + bool valid; // True if this token has been initialized +#endif + Kind kind; // The token's kind + bool lineBreak; // True if line break precedes this token + uint32 pos; // Source position of this token + const StringAtom *id; // The token's characters; non-nil for + // identifiers, keywords, and regular + // expressions only + String chars; // The token's characters; valid for strings, units, + // numbers, and regular expression flags only + float64 value; // The token's value (numbers only) + +#ifdef DEBUG + Token(): valid(false) {} +#endif + + public: + static void initKeywords(World &world); + static bool isSpecialKind(Kind kind) { + return kind <= regExp || kind == identifier; + } + static const char *kindName(Kind kind) { + ASSERT(uint(kind) < kindsEnd); + return kindNames[kind]; + } + Kind getKind() const {ASSERT(valid); return kind;} + bool hasKind(Kind k) const {ASSERT(valid); return kind == k;} + bool hasIdentifierKind() const { + ASSERT(nonreservedEnd == identifier && kindsEnd == identifier+1); + return kind >= nonreservedBegin; + } + bool getFlag(Flag f) const { + ASSERT(valid); + return (kindFlags[kind] & 1<= kindsWithCharsBegin && + kind < kindsWithCharsEnd); + return chars; + } + float64 getValue() const { + ASSERT(valid && kind == number); + return value; + } + friend Formatter &operator<<(Formatter &f, Kind k) { + f << kindName(k); + return f; + } + void print(Formatter &f, bool debug = false) const; + + friend class Lexer; + }; + +} + +#endif /* token_h___ */ diff --git a/mozilla/js2/src/utilities.cpp b/mozilla/js2/src/utilities.cpp index b449b8745ef..a279114b2f2 100644 --- a/mozilla/js2/src/utilities.cpp +++ b/mozilla/js2/src/utilities.cpp @@ -1,43 +1,48 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#include -#include #include "utilities.h" - -#ifdef WIN32 - #include +#ifdef DEBUG +# include +# ifdef WIN32 +# include +# include +# endif #endif -#ifdef XP_MAC - #include - #include -#endif - -namespace JS = JavaScript; - - -// -// Assertions -// - - +namespace JavaScript +{ + #ifdef DEBUG #ifdef XP_MAC // PStrFromCStr converts the source C string to a destination @@ -45,2519 +50,111 @@ namespace JS = JavaScript; // be truncated to fit into an Str255 if necessary. // If the C String pointer is NULL, the pascal string's length is // set to zero. -static void PStrFromCStr(const char* src, Str255 &dst) -{ - int length = 0; - - if (src) + static void + PStrFromCStr(const char* src, Str255 &dst) { - char *p = reinterpret_cast(&dst[1]); - int spaceLeft = 255; - char ch; - while ((ch = *src++) != 0) { - *p++ = ch; - if (--spaceLeft == 0) - break; + int length = 0; + + if (src) + { + char *p = reinterpret_cast(&dst[1]); + int spaceLeft = 255; + char ch; + while ((ch = *src++) != 0) { + *p++ = ch; + if (--spaceLeft == 0) + break; + } + length = 255 - spaceLeft; } - length = 255 - spaceLeft; + dst[0] = (uchar)length; } - dst[0] = (uchar)length; -} - -static void jsdebugstr(const char *debuggerMsg) -{ - Str255 pStr; - PStrFromCStr(debuggerMsg, pStr); - DebugStr(pStr); -} - -static void dprintf(const char *format, ...) -{ - std::va_list ap; - char buffer[4096]; + static void + jsdebugstr(const char *debuggerMsg) + { + Str255 pStr; + + PStrFromCStr(debuggerMsg, pStr); + DebugStr(pStr); + } - va_start(ap, format); - std::vsprintf(buffer, format, ap); - va_end(ap); - - jsdebugstr(buffer); -} + static void + dprintf(const char *format, ...) + { + std::va_list ap; + char buffer[4096]; + + va_start(ap, format); + std::vsprintf(buffer, format, ap); + va_end(ap); + + jsdebugstr(buffer); + } #endif /* XP_MAC */ - - -void JS::Assert(const char *s, const char *file, int line) -{ + + + void + Assert(const char *s, const char *file, int line) + { #if defined(XP_UNIX) || defined(XP_OS2) - fprintf(std::stderr, "Assertion failure: %s, at %s:%d\n", s, file, line); + fprintf(std::stderr, "Assertion failure: %s, at %s:%d\n", s, file, line); #endif #ifdef XP_MAC - dprintf("Assertion failure: %s, at %s:%d\n", s, file, line); + dprintf("Assertion failure: %s, at %s:%d\n", s, file, line); #endif #ifdef WIN32 - DebugBreak(); + DebugBreak(); #endif #ifndef XP_MAC - abort(); + abort(); #endif -} + } #endif /* DEBUG */ - -// -// Bit manipulation -// - - // Return lg2 of the least power of 2 greater than or equal to n. // Return 0 if n is 0 or 1. -uint JS::ceilingLog2(uint32 n) -{ - uint log2 = 0; - - if (n & (n-1)) - log2++; - if (n >> 16) - log2 += 16, n >>= 16; - if (n >> 8) - log2 += 8, n >>= 8; - if (n >> 4) - log2 += 4, n >>= 4; - if (n >> 2) - log2 += 2, n >>= 2; - if (n >> 1) - log2++; - return log2; -} - + uint + ceilingLog2(uint32 n) + { + uint log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; + } + // Return lg2 of the greatest power of 2 less than or equal to n. // This really just finds the highest set bit in the word. // Return 0 if n is 0 or 1. -uint JS::floorLog2(uint32 n) -{ - uint log2 = 0; - - if (n >> 16) - log2 += 16, n >>= 16; - if (n >> 8) - log2 += 8, n >>= 8; - if (n >> 4) - log2 += 4, n >>= 4; - if (n >> 2) - log2 += 2, n >>= 2; - if (n >> 1) - log2++; - return log2; + uint + floorLog2(uint32 n) + { + uint log2 = 0; + + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; + } + } - - - -// -// Unicode UTF-16 characters and strings -// - - -#ifdef _WIN32 // Microsoft VC6 bug: String constructor and append limited to char16 iterators -// Return a String containing the characters of the null-terminated C string cstr -// (without the trailing null). -JS::String JS::widenCString(const char *cstr) -{ - size_t len = strlen(cstr); - String s(len, uni::null); - std::transform(cstr, cstr+len, s.begin(), widen); - return s; -} - - -// Widen and append length characters starting at chars to the end of str. -void JS::appendChars(String &str, const char *chars, size_t length) -{ - String::size_type strLen = str.size(); - str.append(length, uni::null); - std::transform(chars, chars+length, str.begin()+strLen, widen); -} - - -// Widen and insert length characters starting at chars into the given position of str. -void JS::insertChars(String &str, String::size_type pos, const char *chars, size_t length) -{ - str.insert(pos, length, uni::null); - std::transform(chars, chars+length, str.begin()+pos, widen); -} -#endif - - -// Widen and insert the null-terminated string cstr into the given position of str. -void JS::insertChars(String &str, String::size_type pos, const char *cstr) -{ - insertChars(str, pos, cstr, strlen(cstr)); -} - - -// Widen and append the null-terminated string cstr to the end of str. -// Return str. -JS::String &JS::operator+=(String &str, const char *cstr) -{ - appendChars(str, cstr, strlen(cstr)); - return str; -} - - -// Return the concatenation of str and the null-terminated string cstr. -JS::String JS::operator+(const String &str, const char *cstr) -{ - return str + widenCString(cstr); -} - - -// Return the concatenation of the null-terminated string cstr and str. -JS::String JS::operator+(const char *cstr, const String &str) -{ - String s = widenCString(cstr); - s += str; - return s; -} - - -// From java.lang.Character: -// -// The character properties are currently encoded into 32 bits in the -// following manner: -// -// 10 bits signed offset used for converting case -// 1 bit if 1, adding the signed offset converts the character to -// lowercase -// 1 bit if 1, subtracting the signed offset converts the character to -// uppercase -// 1 bit if 1, character has a titlecase equivalent (possibly itself) -// 3 bits 0 May not be part of an identifier -// 1 Format control -// 2 May start or continue a JS identifier (includes $ and _) -// 3 May continue a JS identifier -// 4 Behaves like a white space character (but not line break) -// 5 Behaves like a line break character -// 2 bits 0 this character has no numeric property -// 1 adding the digit offset to the character code and then -// masking with 0x1F will produce the desired numeric value -// 2 this character has a "strange" numeric value -// 3 a JS supradecimal digit: adding the digit offset to the -// character code, then masking with 0x1F, then adding 10 -// will produce the desired numeric value -// 5 bits digit offset -// 4 bits reserved for future use -// 5 bits character type - - -// The X table has 1024 entries for a total of 1024 bytes. -const uint8 JS::CharInfo::x[] = { - 0, 1, 2, 3, 4, 5, 6, 7, // 0x0000 - 8, 9, 10, 11, 12, 13, 14, 15, // 0x0200 - 16, 17, 18, 19, 20, 21, 22, 23, // 0x0400 - 24, 25, 26, 27, 28, 28, 28, 28, // 0x0600 - 28, 28, 28, 28, 29, 30, 31, 32, // 0x0800 - 33, 34, 35, 36, 37, 38, 39, 40, // 0x0A00 - 41, 42, 43, 44, 45, 46, 28, 28, // 0x0C00 - 47, 48, 49, 50, 51, 52, 53, 28, // 0x0E00 - 28, 28, 54, 55, 56, 57, 58, 59, // 0x1000 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1200 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1400 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1600 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1800 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1A00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x1C00 - 60, 60, 61, 62, 63, 64, 65, 66, // 0x1E00 - 67, 68, 69, 70, 71, 72, 73, 74, // 0x2000 - 75, 75, 75, 76, 77, 78, 28, 28, // 0x2200 - 79, 80, 81, 82, 83, 83, 84, 85, // 0x2400 - 86, 85, 28, 28, 87, 88, 89, 28, // 0x2600 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x2800 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x2A00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x2C00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x2E00 - 90, 91, 92, 93, 94, 56, 95, 28, // 0x3000 - 96, 97, 98, 99, 83, 100, 83, 101, // 0x3200 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3400 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3600 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3800 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3A00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3C00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x3E00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4000 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4200 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4400 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4600 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4800 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4A00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0x4C00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x4E00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5A00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5C00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x5E00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6A00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6C00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x6E00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7A00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7C00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x7E00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8A00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8C00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x8E00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9A00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0x9C00 - 56, 56, 56, 56, 56, 56, 102, 28, // 0x9E00 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xA000 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xA200 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xA400 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xA600 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xA800 - 28, 28, 28, 28, 28, 28, 28, 28, // 0xAA00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xAC00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xAE00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xB000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xB200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xB400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xB600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xB800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xBA00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xBC00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xBE00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xC000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xC200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xC400 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xC600 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xC800 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xCA00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xCC00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xCE00 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xD000 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xD200 - 56, 56, 56, 56, 56, 56, 56, 56, // 0xD400 - 56, 56, 56, 56, 56, 56, 103, 28, // 0xD600 - 104, 104, 104, 104, 104, 104, 104, 104, // 0xD800 - 104, 104, 104, 104, 104, 104, 104, 104, // 0xDA00 - 104, 104, 104, 104, 104, 104, 104, 104, // 0xDC00 - 104, 104, 104, 104, 104, 104, 104, 104, // 0xDE00 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xE000 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xE200 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xE400 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xE600 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xE800 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xEA00 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xEC00 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xEE00 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xF000 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xF200 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xF400 - 105, 105, 105, 105, 105, 105, 105, 105, // 0xF600 - 105, 105, 105, 105, 56, 56, 56, 56, // 0xF800 - 106, 28, 28, 28, 107, 108, 109, 110, // 0xFA00 - 56, 56, 56, 56, 111, 112, 113, 114, // 0xFC00 - 115, 116, 56, 117, 118, 119, 120, 121 // 0xFE00 -}; - - -// The Y table has 7808 entries for a total of 7808 bytes. -const uint8 JS::CharInfo::y[] = { - 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 0, 1, 14, 1, 1, 14, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 2, 3, 3, 3, 4, 3, 3, 3, // 0 - 5, 6, 3, 7, 3, 8, 3, 3, // 0 - 9, 9, 9, 9, 9, 9, 9, 9, // 0 - 9, 9, 3, 3, 7, 7, 7, 3, // 0 - 3, 10, 10, 10, 10, 10, 10, 10, // 1 - 10, 10, 10, 10, 10, 10, 10, 10, // 1 - 10, 10, 10, 10, 10, 10, 10, 10, // 1 - 10, 10, 10, 5, 3, 6, 11, 12, // 1 - 11, 13, 13, 13, 13, 13, 13, 13, // 1 - 13, 13, 13, 13, 13, 13, 13, 13, // 1 - 13, 13, 13, 13, 13, 13, 13, 13, // 1 - 13, 13, 13, 5, 7, 6, 7, 0, // 1 - 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 2, 3, 4, 4, 4, 4, 15, 15, // 2 - 11, 15, 16, 5, 7, 8, 15, 11, // 2 - 15, 7, 17, 17, 11, 16, 15, 3, // 2 - 11, 18, 16, 6, 19, 19, 19, 3, // 2 - 20, 20, 20, 20, 20, 20, 20, 20, // 3 - 20, 20, 20, 20, 20, 20, 20, 20, // 3 - 20, 20, 20, 20, 20, 20, 20, 7, // 3 - 20, 20, 20, 20, 20, 20, 20, 16, // 3 - 21, 21, 21, 21, 21, 21, 21, 21, // 3 - 21, 21, 21, 21, 21, 21, 21, 21, // 3 - 21, 21, 21, 21, 21, 21, 21, 7, // 3 - 21, 21, 21, 21, 21, 21, 21, 22, // 3 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 23, 24, 23, 24, 23, 24, 23, 24, // 4 - 25, 26, 23, 24, 23, 24, 23, 24, // 4 - 16, 23, 24, 23, 24, 23, 24, 23, // 4 - 24, 23, 24, 23, 24, 23, 24, 23, // 5 - 24, 16, 23, 24, 23, 24, 23, 24, // 5 - 23, 24, 23, 24, 23, 24, 23, 24, // 5 - 23, 24, 23, 24, 23, 24, 23, 24, // 5 - 23, 24, 23, 24, 23, 24, 23, 24, // 5 - 23, 24, 23, 24, 23, 24, 23, 24, // 5 - 23, 24, 23, 24, 23, 24, 23, 24, // 5 - 27, 23, 24, 23, 24, 23, 24, 28, // 5 - 16, 29, 23, 24, 23, 24, 30, 23, // 6 - 24, 31, 31, 23, 24, 16, 32, 32, // 6 - 33, 23, 24, 31, 34, 16, 35, 36, // 6 - 23, 24, 16, 16, 35, 37, 16, 38, // 6 - 23, 24, 23, 24, 23, 24, 38, 23, // 6 - 24, 39, 40, 16, 23, 24, 39, 23, // 6 - 24, 41, 41, 23, 24, 23, 24, 42, // 6 - 23, 24, 16, 40, 23, 24, 40, 40, // 6 - 40, 40, 40, 40, 43, 44, 45, 43, // 7 - 44, 45, 43, 44, 45, 23, 24, 23, // 7 - 24, 23, 24, 23, 24, 23, 24, 23, // 7 - 24, 23, 24, 23, 24, 16, 23, 24, // 7 - 23, 24, 23, 24, 23, 24, 23, 24, // 7 - 23, 24, 23, 24, 23, 24, 23, 24, // 7 - 16, 43, 44, 45, 23, 24, 46, 46, // 7 - 46, 46, 23, 24, 23, 24, 23, 24, // 7 - 23, 24, 23, 24, 23, 24, 23, 24, // 8 - 23, 24, 23, 24, 23, 24, 23, 24, // 8 - 23, 24, 23, 24, 23, 24, 23, 24, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 8 - 46, 46, 46, 46, 46, 46, 46, 46, // 9 - 46, 46, 46, 46, 46, 46, 46, 46, // 9 - 16, 16, 16, 47, 48, 16, 49, 49, // 9 - 50, 50, 16, 51, 16, 16, 16, 16, // 9 - 49, 16, 16, 52, 16, 16, 16, 16, // 9 - 53, 54, 16, 16, 16, 16, 16, 54, // 9 - 16, 16, 55, 16, 16, 16, 16, 16, // 9 - 16, 16, 16, 16, 16, 16, 16, 16, // 9 - 16, 16, 16, 56, 16, 16, 16, 16, // 10 - 56, 16, 57, 57, 16, 16, 16, 16, // 10 - 16, 16, 58, 16, 16, 16, 16, 16, // 10 - 16, 16, 16, 16, 16, 16, 16, 16, // 10 - 16, 16, 16, 16, 16, 16, 16, 16, // 10 - 16, 46, 46, 46, 46, 46, 46, 46, // 10 - 59, 59, 59, 59, 59, 59, 59, 59, // 10 - 59, 11, 11, 59, 59, 59, 59, 59, // 10 - 59, 59, 11, 11, 11, 11, 11, 11, // 11 - 11, 11, 11, 11, 11, 11, 11, 11, // 11 - 59, 59, 11, 11, 11, 11, 11, 11, // 11 - 11, 11, 11, 11, 11, 11, 11, 46, // 11 - 59, 59, 59, 59, 59, 11, 11, 11, // 11 - 11, 11, 46, 46, 46, 46, 46, 46, // 11 - 46, 46, 46, 46, 46, 46, 46, 46, // 11 - 46, 46, 46, 46, 46, 46, 46, 46, // 11 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 60, 60, // 12 - 60, 60, 60, 60, 60, 60, 46, 46, // 13 - 46, 46, 46, 46, 46, 46, 46, 46, // 13 - 46, 46, 46, 46, 46, 46, 46, 46, // 13 - 46, 46, 46, 46, 46, 46, 46, 46, // 13 - 60, 60, 46, 46, 46, 46, 46, 46, // 13 - 46, 46, 46, 46, 46, 46, 46, 46, // 13 - 46, 46, 46, 46, 3, 3, 46, 46, // 13 - 46, 46, 59, 46, 46, 46, 3, 46, // 13 - 46, 46, 46, 46, 11, 11, 61, 3, // 14 - 62, 62, 62, 46, 63, 46, 64, 64, // 14 - 16, 20, 20, 20, 20, 20, 20, 20, // 14 - 20, 20, 20, 20, 20, 20, 20, 20, // 14 - 20, 20, 46, 20, 20, 20, 20, 20, // 14 - 20, 20, 20, 20, 65, 66, 66, 66, // 14 - 16, 21, 21, 21, 21, 21, 21, 21, // 14 - 21, 21, 21, 21, 21, 21, 21, 21, // 14 - 21, 21, 16, 21, 21, 21, 21, 21, // 15 - 21, 21, 21, 21, 67, 68, 68, 46, // 15 - 69, 70, 38, 38, 38, 71, 72, 46, // 15 - 46, 46, 38, 46, 38, 46, 38, 46, // 15 - 38, 46, 23, 24, 23, 24, 23, 24, // 15 - 23, 24, 23, 24, 23, 24, 23, 24, // 15 - 73, 74, 16, 40, 46, 46, 46, 46, // 15 - 46, 46, 46, 46, 46, 46, 46, 46, // 15 - 46, 75, 75, 75, 75, 75, 75, 75, // 16 - 75, 75, 75, 75, 75, 46, 75, 75, // 16 - 20, 20, 20, 20, 20, 20, 20, 20, // 16 - 20, 20, 20, 20, 20, 20, 20, 20, // 16 - 20, 20, 20, 20, 20, 20, 20, 20, // 16 - 20, 20, 20, 20, 20, 20, 20, 20, // 16 - 21, 21, 21, 21, 21, 21, 21, 21, // 16 - 21, 21, 21, 21, 21, 21, 21, 21, // 16 - 21, 21, 21, 21, 21, 21, 21, 21, // 17 - 21, 21, 21, 21, 21, 21, 21, 21, // 17 - 46, 74, 74, 74, 74, 74, 74, 74, // 17 - 74, 74, 74, 74, 74, 46, 74, 74, // 17 - 23, 24, 23, 24, 23, 24, 23, 24, // 17 - 23, 24, 23, 24, 23, 24, 23, 24, // 17 - 23, 24, 23, 24, 23, 24, 23, 24, // 17 - 23, 24, 23, 24, 23, 24, 23, 24, // 17 - 23, 24, 15, 60, 60, 60, 60, 46, // 18 - 46, 46, 46, 46, 46, 46, 46, 46, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 23, 24, 23, 24, 23, 24, 23, 24, // 18 - 40, 23, 24, 23, 24, 46, 46, 23, // 19 - 24, 46, 46, 23, 24, 46, 46, 46, // 19 - 23, 24, 23, 24, 23, 24, 23, 24, // 19 - 23, 24, 23, 24, 23, 24, 23, 24, // 19 - 23, 24, 23, 24, 23, 24, 23, 24, // 19 - 23, 24, 23, 24, 46, 46, 23, 24, // 19 - 23, 24, 23, 24, 23, 24, 46, 46, // 19 - 23, 24, 46, 46, 46, 46, 46, 46, // 19 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 46, 46, 46, 46, 46, 46, 46, // 20 - 46, 76, 76, 76, 76, 76, 76, 76, // 20 - 76, 76, 76, 76, 76, 76, 76, 76, // 20 - 76, 76, 76, 76, 76, 76, 76, 76, // 21 - 76, 76, 76, 76, 76, 76, 76, 76, // 21 - 76, 76, 76, 76, 76, 76, 76, 46, // 21 - 46, 59, 3, 3, 3, 3, 3, 3, // 21 - 46, 77, 77, 77, 77, 77, 77, 77, // 21 - 77, 77, 77, 77, 77, 77, 77, 77, // 21 - 77, 77, 77, 77, 77, 77, 77, 77, // 21 - 77, 77, 77, 77, 77, 77, 77, 77, // 21 - 77, 77, 77, 77, 77, 77, 77, 16, // 22 - 46, 3, 46, 46, 46, 46, 46, 46, // 22 - 46, 60, 60, 60, 60, 60, 60, 60, // 22 - 60, 60, 60, 60, 60, 60, 60, 60, // 22 - 60, 60, 46, 60, 60, 60, 60, 60, // 22 - 60, 60, 60, 60, 60, 60, 60, 60, // 22 - 60, 60, 60, 60, 60, 60, 60, 60, // 22 - 60, 60, 46, 60, 60, 60, 3, 60, // 22 - 3, 60, 60, 3, 60, 46, 46, 46, // 23 - 46, 46, 46, 46, 46, 46, 46, 46, // 23 - 40, 40, 40, 40, 40, 40, 40, 40, // 23 - 40, 40, 40, 40, 40, 40, 40, 40, // 23 - 40, 40, 40, 40, 40, 40, 40, 40, // 23 - 40, 40, 40, 46, 46, 46, 46, 46, // 23 - 40, 40, 40, 3, 3, 46, 46, 46, // 23 - 46, 46, 46, 46, 46, 46, 46, 46, // 23 - 46, 46, 46, 46, 46, 46, 46, 46, // 24 - 46, 46, 46, 46, 3, 46, 46, 46, // 24 - 46, 46, 46, 46, 46, 46, 46, 46, // 24 - 46, 46, 46, 3, 46, 46, 46, 3, // 24 - 46, 40, 40, 40, 40, 40, 40, 40, // 24 - 40, 40, 40, 40, 40, 40, 40, 40, // 24 - 40, 40, 40, 40, 40, 40, 40, 40, // 24 - 40, 40, 40, 46, 46, 46, 46, 46, // 24 - 59, 40, 40, 40, 40, 40, 40, 40, // 25 - 40, 40, 40, 60, 60, 60, 60, 60, // 25 - 60, 60, 60, 46, 46, 46, 46, 46, // 25 - 46, 46, 46, 46, 46, 46, 46, 46, // 25 - 78, 78, 78, 78, 78, 78, 78, 78, // 25 - 78, 78, 3, 3, 3, 3, 46, 46, // 25 - 60, 40, 40, 40, 40, 40, 40, 40, // 25 - 40, 40, 40, 40, 40, 40, 40, 40, // 25 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 26 - 46, 46, 40, 40, 40, 40, 40, 46, // 26 - 40, 40, 40, 40, 40, 40, 40, 40, // 27 - 40, 40, 40, 40, 40, 40, 40, 46, // 27 - 40, 40, 40, 40, 3, 40, 60, 60, // 27 - 60, 60, 60, 60, 60, 79, 79, 60, // 27 - 60, 60, 60, 60, 60, 59, 59, 60, // 27 - 60, 15, 60, 60, 60, 60, 46, 46, // 27 - 9, 9, 9, 9, 9, 9, 9, 9, // 27 - 9, 9, 46, 46, 46, 46, 46, 46, // 27 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 46, 46, 46, 46, 46, 46, 46, // 28 - 46, 60, 60, 80, 46, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 40, 40, 40, 40, 40, 40, // 29 - 40, 40, 46, 46, 60, 40, 80, 80, // 29 - 80, 60, 60, 60, 60, 60, 60, 60, // 30 - 60, 80, 80, 80, 80, 60, 46, 46, // 30 - 15, 60, 60, 60, 60, 46, 46, 46, // 30 - 40, 40, 40, 40, 40, 40, 40, 40, // 30 - 40, 40, 60, 60, 3, 3, 81, 81, // 30 - 81, 81, 81, 81, 81, 81, 81, 81, // 30 - 3, 46, 46, 46, 46, 46, 46, 46, // 30 - 46, 46, 46, 46, 46, 46, 46, 46, // 30 - 46, 60, 80, 80, 46, 40, 40, 40, // 31 - 40, 40, 40, 40, 40, 46, 46, 40, // 31 - 40, 46, 46, 40, 40, 40, 40, 40, // 31 - 40, 40, 40, 40, 40, 40, 40, 40, // 31 - 40, 40, 40, 40, 40, 40, 40, 40, // 31 - 40, 46, 40, 40, 40, 40, 40, 40, // 31 - 40, 46, 40, 46, 46, 46, 40, 40, // 31 - 40, 40, 46, 46, 60, 46, 80, 80, // 31 - 80, 60, 60, 60, 60, 46, 46, 80, // 32 - 80, 46, 46, 80, 80, 60, 46, 46, // 32 - 46, 46, 46, 46, 46, 46, 46, 80, // 32 - 46, 46, 46, 46, 40, 40, 46, 40, // 32 - 40, 40, 60, 60, 46, 46, 81, 81, // 32 - 81, 81, 81, 81, 81, 81, 81, 81, // 32 - 40, 40, 4, 4, 82, 82, 82, 82, // 32 - 19, 83, 15, 46, 46, 46, 46, 46, // 32 - 46, 46, 60, 46, 46, 40, 40, 40, // 33 - 40, 40, 40, 46, 46, 46, 46, 40, // 33 - 40, 46, 46, 40, 40, 40, 40, 40, // 33 - 40, 40, 40, 40, 40, 40, 40, 40, // 33 - 40, 40, 40, 40, 40, 40, 40, 40, // 33 - 40, 46, 40, 40, 40, 40, 40, 40, // 33 - 40, 46, 40, 40, 46, 40, 40, 46, // 33 - 40, 40, 46, 46, 60, 46, 80, 80, // 33 - 80, 60, 60, 46, 46, 46, 46, 60, // 34 - 60, 46, 46, 60, 60, 60, 46, 46, // 34 - 46, 46, 46, 46, 46, 46, 46, 46, // 34 - 46, 40, 40, 40, 40, 46, 40, 46, // 34 - 46, 46, 46, 46, 46, 46, 81, 81, // 34 - 81, 81, 81, 81, 81, 81, 81, 81, // 34 - 60, 60, 40, 40, 40, 46, 46, 46, // 34 - 46, 46, 46, 46, 46, 46, 46, 46, // 34 - 46, 60, 60, 80, 46, 40, 40, 40, // 35 - 40, 40, 40, 40, 46, 40, 46, 40, // 35 - 40, 40, 46, 40, 40, 40, 40, 40, // 35 - 40, 40, 40, 40, 40, 40, 40, 40, // 35 - 40, 40, 40, 40, 40, 40, 40, 40, // 35 - 40, 46, 40, 40, 40, 40, 40, 40, // 35 - 40, 46, 40, 40, 46, 40, 40, 40, // 35 - 40, 40, 46, 46, 60, 40, 80, 80, // 35 - 80, 60, 60, 60, 60, 60, 46, 60, // 36 - 60, 80, 46, 80, 80, 60, 46, 46, // 36 - 15, 46, 46, 46, 46, 46, 46, 46, // 36 - 46, 46, 46, 46, 46, 46, 46, 46, // 36 - 40, 46, 46, 46, 46, 46, 81, 81, // 36 - 81, 81, 81, 81, 81, 81, 81, 81, // 36 - 46, 46, 46, 46, 46, 46, 46, 46, // 36 - 46, 46, 46, 46, 46, 46, 46, 46, // 36 - 46, 60, 80, 80, 46, 40, 40, 40, // 37 - 40, 40, 40, 40, 40, 46, 46, 40, // 37 - 40, 46, 46, 40, 40, 40, 40, 40, // 37 - 40, 40, 40, 40, 40, 40, 40, 40, // 37 - 40, 40, 40, 40, 40, 40, 40, 40, // 37 - 40, 46, 40, 40, 40, 40, 40, 40, // 37 - 40, 46, 40, 40, 46, 46, 40, 40, // 37 - 40, 40, 46, 46, 60, 40, 80, 60, // 37 - 80, 60, 60, 60, 46, 46, 46, 80, // 38 - 80, 46, 46, 80, 80, 60, 46, 46, // 38 - 46, 46, 46, 46, 46, 46, 60, 80, // 38 - 46, 46, 46, 46, 40, 40, 46, 40, // 38 - 40, 40, 46, 46, 46, 46, 81, 81, // 38 - 81, 81, 81, 81, 81, 81, 81, 81, // 38 - 15, 46, 46, 46, 46, 46, 46, 46, // 38 - 46, 46, 46, 46, 46, 46, 46, 46, // 38 - 46, 46, 60, 80, 46, 40, 40, 40, // 39 - 40, 40, 40, 46, 46, 46, 40, 40, // 39 - 40, 46, 40, 40, 40, 40, 46, 46, // 39 - 46, 40, 40, 46, 40, 46, 40, 40, // 39 - 46, 46, 46, 40, 40, 46, 46, 46, // 39 - 40, 40, 40, 46, 46, 46, 40, 40, // 39 - 40, 40, 40, 40, 40, 40, 46, 40, // 39 - 40, 40, 46, 46, 46, 46, 80, 80, // 39 - 60, 80, 80, 46, 46, 46, 80, 80, // 40 - 80, 46, 80, 80, 80, 60, 46, 46, // 40 - 46, 46, 46, 46, 46, 46, 46, 80, // 40 - 46, 46, 46, 46, 46, 46, 46, 46, // 40 - 46, 46, 46, 46, 46, 46, 46, 81, // 40 - 81, 81, 81, 81, 81, 81, 81, 81, // 40 - 84, 19, 19, 46, 46, 46, 46, 46, // 40 - 46, 46, 46, 46, 46, 46, 46, 46, // 40 - 46, 80, 80, 80, 46, 40, 40, 40, // 41 - 40, 40, 40, 40, 40, 46, 40, 40, // 41 - 40, 46, 40, 40, 40, 40, 40, 40, // 41 - 40, 40, 40, 40, 40, 40, 40, 40, // 41 - 40, 40, 40, 40, 40, 40, 40, 40, // 41 - 40, 46, 40, 40, 40, 40, 40, 40, // 41 - 40, 40, 40, 40, 46, 40, 40, 40, // 41 - 40, 40, 46, 46, 46, 46, 60, 60, // 41 - 60, 80, 80, 80, 80, 46, 60, 60, // 42 - 60, 46, 60, 60, 60, 60, 46, 46, // 42 - 46, 46, 46, 46, 46, 60, 60, 46, // 42 - 46, 46, 46, 46, 46, 46, 46, 46, // 42 - 40, 40, 46, 46, 46, 46, 81, 81, // 42 - 81, 81, 81, 81, 81, 81, 81, 81, // 42 - 46, 46, 46, 46, 46, 46, 46, 46, // 42 - 46, 46, 46, 46, 46, 46, 46, 46, // 42 - 46, 46, 80, 80, 46, 40, 40, 40, // 43 - 40, 40, 40, 40, 40, 46, 40, 40, // 43 - 40, 46, 40, 40, 40, 40, 40, 40, // 43 - 40, 40, 40, 40, 40, 40, 40, 40, // 43 - 40, 40, 40, 40, 40, 40, 40, 40, // 43 - 40, 46, 40, 40, 40, 40, 40, 40, // 43 - 40, 40, 40, 40, 46, 40, 40, 40, // 43 - 40, 40, 46, 46, 46, 46, 80, 60, // 43 - 80, 80, 80, 80, 80, 46, 60, 80, // 44 - 80, 46, 80, 80, 60, 60, 46, 46, // 44 - 46, 46, 46, 46, 46, 80, 80, 46, // 44 - 46, 46, 46, 46, 46, 46, 40, 46, // 44 - 40, 40, 46, 46, 46, 46, 81, 81, // 44 - 81, 81, 81, 81, 81, 81, 81, 81, // 44 - 46, 46, 46, 46, 46, 46, 46, 46, // 44 - 46, 46, 46, 46, 46, 46, 46, 46, // 44 - 46, 46, 80, 80, 46, 40, 40, 40, // 45 - 40, 40, 40, 40, 40, 46, 40, 40, // 45 - 40, 46, 40, 40, 40, 40, 40, 40, // 45 - 40, 40, 40, 40, 40, 40, 40, 40, // 45 - 40, 40, 40, 40, 40, 40, 40, 40, // 45 - 40, 46, 40, 40, 40, 40, 40, 40, // 45 - 40, 40, 40, 40, 40, 40, 40, 40, // 45 - 40, 40, 46, 46, 46, 46, 80, 80, // 45 - 80, 60, 60, 60, 46, 46, 80, 80, // 46 - 80, 46, 80, 80, 80, 60, 46, 46, // 46 - 46, 46, 46, 46, 46, 46, 46, 80, // 46 - 46, 46, 46, 46, 46, 46, 46, 46, // 46 - 40, 40, 46, 46, 46, 46, 81, 81, // 46 - 81, 81, 81, 81, 81, 81, 81, 81, // 46 - 46, 46, 46, 46, 46, 46, 46, 46, // 46 - 46, 46, 46, 46, 46, 46, 46, 46, // 46 - 46, 40, 40, 40, 40, 40, 40, 40, // 47 - 40, 40, 40, 40, 40, 40, 40, 40, // 47 - 40, 40, 40, 40, 40, 40, 40, 40, // 47 - 40, 40, 40, 40, 40, 40, 40, 40, // 47 - 40, 40, 40, 40, 40, 40, 40, 40, // 47 - 40, 40, 40, 40, 40, 40, 40, 3, // 47 - 40, 60, 40, 40, 60, 60, 60, 60, // 47 - 60, 60, 60, 46, 46, 46, 46, 4, // 47 - 40, 40, 40, 40, 40, 40, 59, 60, // 48 - 60, 60, 60, 60, 60, 60, 60, 15, // 48 - 9, 9, 9, 9, 9, 9, 9, 9, // 48 - 9, 9, 3, 3, 46, 46, 46, 46, // 48 - 46, 46, 46, 46, 46, 46, 46, 46, // 48 - 46, 46, 46, 46, 46, 46, 46, 46, // 48 - 46, 46, 46, 46, 46, 46, 46, 46, // 48 - 46, 46, 46, 46, 46, 46, 46, 46, // 48 - 46, 40, 40, 46, 40, 46, 46, 40, // 49 - 40, 46, 40, 46, 46, 40, 46, 46, // 49 - 46, 46, 46, 46, 40, 40, 40, 40, // 49 - 46, 40, 40, 40, 40, 40, 40, 40, // 49 - 46, 40, 40, 40, 46, 40, 46, 40, // 49 - 46, 46, 40, 40, 46, 40, 40, 3, // 49 - 40, 60, 40, 40, 60, 60, 60, 60, // 49 - 60, 60, 46, 60, 60, 40, 46, 46, // 49 - 40, 40, 40, 40, 40, 46, 59, 46, // 50 - 60, 60, 60, 60, 60, 60, 46, 46, // 50 - 9, 9, 9, 9, 9, 9, 9, 9, // 50 - 9, 9, 46, 46, 40, 40, 46, 46, // 50 - 46, 46, 46, 46, 46, 46, 46, 46, // 50 - 46, 46, 46, 46, 46, 46, 46, 46, // 50 - 46, 46, 46, 46, 46, 46, 46, 46, // 50 - 46, 46, 46, 46, 46, 46, 46, 46, // 50 - 15, 15, 15, 15, 3, 3, 3, 3, // 51 - 3, 3, 3, 3, 3, 3, 3, 3, // 51 - 3, 3, 3, 15, 15, 15, 15, 15, // 51 - 60, 60, 15, 15, 15, 15, 15, 15, // 51 - 78, 78, 78, 78, 78, 78, 78, 78, // 51 - 78, 78, 85, 85, 85, 85, 85, 85, // 51 - 85, 85, 85, 85, 15, 60, 15, 60, // 51 - 15, 60, 5, 6, 5, 6, 80, 80, // 51 - 40, 40, 40, 40, 40, 40, 40, 40, // 52 - 46, 40, 40, 40, 40, 40, 40, 40, // 52 - 40, 40, 40, 40, 40, 40, 40, 40, // 52 - 40, 40, 40, 40, 40, 40, 40, 40, // 52 - 40, 40, 40, 40, 40, 40, 40, 40, // 52 - 40, 40, 46, 46, 46, 46, 46, 46, // 52 - 46, 60, 60, 60, 60, 60, 60, 60, // 52 - 60, 60, 60, 60, 60, 60, 60, 80, // 52 - 60, 60, 60, 60, 60, 3, 60, 60, // 53 - 60, 60, 60, 60, 46, 46, 46, 46, // 53 - 60, 60, 60, 60, 60, 60, 46, 60, // 53 - 46, 60, 60, 60, 60, 60, 60, 60, // 53 - 60, 60, 60, 60, 60, 60, 60, 60, // 53 - 60, 60, 60, 60, 60, 60, 46, 46, // 53 - 46, 60, 60, 60, 60, 60, 60, 60, // 53 - 46, 60, 46, 46, 46, 46, 46, 46, // 53 - 46, 46, 46, 46, 46, 46, 46, 46, // 54 - 46, 46, 46, 46, 46, 46, 46, 46, // 54 - 46, 46, 46, 46, 46, 46, 46, 46, // 54 - 46, 46, 46, 46, 46, 46, 46, 46, // 54 - 76, 76, 76, 76, 76, 76, 76, 76, // 54 - 76, 76, 76, 76, 76, 76, 76, 76, // 54 - 76, 76, 76, 76, 76, 76, 76, 76, // 54 - 76, 76, 76, 76, 76, 76, 76, 76, // 54 - 76, 76, 76, 76, 76, 76, 46, 46, // 55 - 46, 46, 46, 46, 46, 46, 46, 46, // 55 - 16, 16, 16, 16, 16, 16, 16, 16, // 55 - 16, 16, 16, 16, 16, 16, 16, 16, // 55 - 16, 16, 16, 16, 16, 16, 16, 16, // 55 - 16, 16, 16, 16, 16, 16, 16, 16, // 55 - 16, 16, 16, 16, 16, 16, 16, 46, // 55 - 46, 46, 46, 3, 46, 46, 46, 46, // 55 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 56 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 46, 46, 46, 46, 46, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 57 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 46, 46, 46, 46, 46, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 58 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 40, 40, 40, 40, 40, 40, // 59 - 40, 40, 46, 46, 46, 46, 46, 46, // 59 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 60 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 16, 16, // 61 - 16, 16, 16, 16, 46, 46, 46, 46, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 61 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 23, 24, 23, 24, 23, 24, // 62 - 23, 24, 46, 46, 46, 46, 46, 46, // 62 - 86, 86, 86, 86, 86, 86, 86, 86, // 63 - 87, 87, 87, 87, 87, 87, 87, 87, // 63 - 86, 86, 86, 86, 86, 86, 46, 46, // 63 - 87, 87, 87, 87, 87, 87, 46, 46, // 63 - 86, 86, 86, 86, 86, 86, 86, 86, // 63 - 87, 87, 87, 87, 87, 87, 87, 87, // 63 - 86, 86, 86, 86, 86, 86, 86, 86, // 63 - 87, 87, 87, 87, 87, 87, 87, 87, // 63 - 86, 86, 86, 86, 86, 86, 46, 46, // 64 - 87, 87, 87, 87, 87, 87, 46, 46, // 64 - 16, 86, 16, 86, 16, 86, 16, 86, // 64 - 46, 87, 46, 87, 46, 87, 46, 87, // 64 - 86, 86, 86, 86, 86, 86, 86, 86, // 64 - 87, 87, 87, 87, 87, 87, 87, 87, // 64 - 88, 88, 89, 89, 89, 89, 90, 90, // 64 - 91, 91, 92, 92, 93, 93, 46, 46, // 64 - 86, 86, 86, 86, 86, 86, 86, 86, // 65 - 87, 87, 87, 87, 87, 87, 87, 87, // 65 - 86, 86, 86, 86, 86, 86, 86, 86, // 65 - 87, 87, 87, 87, 87, 87, 87, 87, // 65 - 86, 86, 86, 86, 86, 86, 86, 86, // 65 - 87, 87, 87, 87, 87, 87, 87, 87, // 65 - 86, 86, 16, 94, 16, 46, 16, 16, // 65 - 87, 87, 95, 95, 96, 11, 38, 11, // 65 - 11, 11, 16, 94, 16, 46, 16, 16, // 66 - 97, 97, 97, 97, 96, 11, 11, 11, // 66 - 86, 86, 16, 16, 46, 46, 16, 16, // 66 - 87, 87, 98, 98, 46, 11, 11, 11, // 66 - 86, 86, 16, 16, 16, 99, 16, 16, // 66 - 87, 87, 100, 100, 101, 11, 11, 11, // 66 - 46, 46, 16, 94, 16, 46, 16, 16, // 66 - 102, 102, 103, 103, 96, 11, 11, 46, // 66 - 2, 2, 2, 2, 2, 2, 2, 2, // 67 - 2, 2, 2, 2, 104, 104, 104, 104, // 67 - 8, 8, 8, 8, 8, 8, 3, 3, // 67 - 5, 6, 5, 5, 5, 6, 5, 5, // 67 - 3, 3, 3, 3, 3, 3, 3, 3, // 67 - 105, 106, 104, 104, 104, 104, 104, 46, // 67 - 3, 3, 3, 3, 3, 3, 3, 3, // 67 - 3, 5, 6, 3, 3, 3, 3, 12, // 67 - 12, 3, 3, 3, 7, 5, 6, 46, // 68 - 46, 46, 46, 46, 46, 46, 46, 46, // 68 - 46, 46, 46, 46, 46, 46, 46, 46, // 68 - 46, 46, 46, 46, 46, 46, 46, 46, // 68 - 46, 46, 46, 46, 46, 46, 46, 46, // 68 - 46, 46, 104, 104, 104, 104, 104, 104, // 68 - 17, 46, 46, 46, 17, 17, 17, 17, // 68 - 17, 17, 7, 7, 7, 5, 6, 16, // 68 - 107, 107, 107, 107, 107, 107, 107, 107, // 69 - 107, 107, 7, 7, 7, 5, 6, 46, // 69 - 46, 46, 46, 46, 46, 46, 46, 46, // 69 - 46, 46, 46, 46, 46, 46, 46, 46, // 69 - 4, 4, 4, 4, 4, 4, 4, 4, // 69 - 4, 4, 4, 4, 46, 46, 46, 46, // 69 - 46, 46, 46, 46, 46, 46, 46, 46, // 69 - 46, 46, 46, 46, 46, 46, 46, 46, // 69 - 46, 46, 46, 46, 46, 46, 46, 46, // 70 - 46, 46, 46, 46, 46, 46, 46, 46, // 70 - 60, 60, 60, 60, 60, 60, 60, 60, // 70 - 60, 60, 60, 60, 60, 79, 79, 79, // 70 - 79, 60, 46, 46, 46, 46, 46, 46, // 70 - 46, 46, 46, 46, 46, 46, 46, 46, // 70 - 46, 46, 46, 46, 46, 46, 46, 46, // 70 - 46, 46, 46, 46, 46, 46, 46, 46, // 70 - 15, 15, 38, 15, 15, 15, 15, 38, // 71 - 15, 15, 16, 38, 38, 38, 16, 16, // 71 - 38, 38, 38, 16, 15, 38, 15, 15, // 71 - 38, 38, 38, 38, 38, 38, 15, 15, // 71 - 15, 15, 15, 15, 38, 15, 38, 15, // 71 - 38, 15, 38, 38, 38, 38, 16, 16, // 71 - 38, 38, 15, 38, 16, 40, 40, 40, // 71 - 40, 46, 46, 46, 46, 46, 46, 46, // 71 - 46, 46, 46, 46, 46, 46, 46, 46, // 72 - 46, 46, 46, 46, 46, 46, 46, 46, // 72 - 46, 46, 46, 19, 19, 19, 19, 19, // 72 - 19, 19, 19, 19, 19, 19, 19, 108, // 72 - 109, 109, 109, 109, 109, 109, 109, 109, // 72 - 109, 109, 109, 109, 110, 110, 110, 110, // 72 - 111, 111, 111, 111, 111, 111, 111, 111, // 72 - 111, 111, 111, 111, 112, 112, 112, 112, // 72 - 113, 113, 113, 46, 46, 46, 46, 46, // 73 - 46, 46, 46, 46, 46, 46, 46, 46, // 73 - 7, 7, 7, 7, 7, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 73 - 15, 15, 15, 15, 15, 15, 15, 15, // 74 - 15, 15, 15, 15, 15, 15, 15, 15, // 74 - 15, 15, 7, 15, 7, 15, 15, 15, // 74 - 15, 15, 15, 15, 15, 15, 15, 15, // 74 - 15, 15, 15, 15, 15, 15, 15, 15, // 74 - 15, 15, 15, 46, 46, 46, 46, 46, // 74 - 46, 46, 46, 46, 46, 46, 46, 46, // 74 - 46, 46, 46, 46, 46, 46, 46, 46, // 74 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 75 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 7, 7, 7, 7, 7, 7, // 76 - 7, 7, 46, 46, 46, 46, 46, 46, // 76 - 46, 46, 46, 46, 46, 46, 46, 46, // 76 - 15, 46, 15, 15, 15, 15, 15, 15, // 77 - 7, 7, 7, 7, 15, 15, 15, 15, // 77 - 15, 15, 15, 15, 15, 15, 15, 15, // 77 - 15, 15, 15, 15, 15, 15, 15, 15, // 77 - 7, 7, 15, 15, 15, 15, 15, 15, // 77 - 15, 5, 6, 15, 15, 15, 15, 15, // 77 - 15, 15, 15, 15, 15, 15, 15, 15, // 77 - 15, 15, 15, 15, 15, 15, 15, 15, // 77 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 78 - 15, 15, 15, 46, 46, 46, 46, 46, // 78 - 15, 15, 15, 15, 15, 15, 15, 15, // 79 - 15, 15, 15, 15, 15, 15, 15, 15, // 79 - 15, 15, 15, 15, 15, 15, 15, 15, // 79 - 15, 15, 15, 15, 15, 15, 15, 15, // 79 - 15, 15, 15, 15, 15, 46, 46, 46, // 79 - 46, 46, 46, 46, 46, 46, 46, 46, // 79 - 46, 46, 46, 46, 46, 46, 46, 46, // 79 - 46, 46, 46, 46, 46, 46, 46, 46, // 79 - 15, 15, 15, 15, 15, 15, 15, 15, // 80 - 15, 15, 15, 46, 46, 46, 46, 46, // 80 - 46, 46, 46, 46, 46, 46, 46, 46, // 80 - 46, 46, 46, 46, 46, 46, 46, 46, // 80 - 114, 114, 114, 114, 114, 114, 114, 114, // 80 - 114, 114, 114, 114, 114, 114, 114, 114, // 80 - 114, 114, 114, 114, 82, 82, 82, 82, // 80 - 82, 82, 82, 82, 82, 82, 82, 82, // 80 - 82, 82, 82, 82, 82, 82, 82, 82, // 81 - 115, 115, 115, 115, 115, 115, 115, 115, // 81 - 115, 115, 115, 115, 115, 115, 115, 115, // 81 - 115, 115, 115, 115, 15, 15, 15, 15, // 81 - 15, 15, 15, 15, 15, 15, 15, 15, // 81 - 15, 15, 15, 15, 15, 15, 15, 15, // 81 - 15, 15, 15, 15, 15, 15, 116, 116, // 81 - 116, 116, 116, 116, 116, 116, 116, 116, // 81 - 116, 116, 116, 116, 116, 116, 116, 116, // 82 - 116, 116, 116, 116, 116, 116, 116, 116, // 82 - 117, 117, 117, 117, 117, 117, 117, 117, // 82 - 117, 117, 117, 117, 117, 117, 117, 117, // 82 - 117, 117, 117, 117, 117, 117, 117, 117, // 82 - 117, 117, 118, 46, 46, 46, 46, 46, // 82 - 46, 46, 46, 46, 46, 46, 46, 46, // 82 - 46, 46, 46, 46, 46, 46, 46, 46, // 82 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 83 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 46, 46, // 84 - 46, 46, 46, 46, 46, 46, 46, 46, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 84 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 85 - 46, 46, 46, 46, 46, 46, 46, 46, // 85 - 46, 46, 46, 46, 46, 46, 46, 46, // 85 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 46, 46, 46, 46, // 86 - 46, 46, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 15, 15, 15, 15, 15, 15, 15, 15, // 86 - 46, 15, 15, 15, 15, 46, 15, 15, // 87 - 15, 15, 46, 46, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 87 - 46, 15, 15, 15, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 87 - 15, 15, 15, 15, 15, 15, 15, 15, // 88 - 15, 15, 15, 15, 46, 15, 46, 15, // 88 - 15, 15, 15, 46, 46, 46, 15, 46, // 88 - 15, 15, 15, 15, 15, 15, 15, 46, // 88 - 46, 15, 15, 15, 15, 15, 15, 15, // 88 - 46, 46, 46, 46, 46, 46, 46, 46, // 88 - 46, 46, 46, 46, 46, 46, 119, 119, // 88 - 119, 119, 119, 119, 119, 119, 119, 119, // 88 - 114, 114, 114, 114, 114, 114, 114, 114, // 89 - 114, 114, 83, 83, 83, 83, 83, 83, // 89 - 83, 83, 83, 83, 15, 46, 46, 46, // 89 - 15, 15, 15, 15, 15, 15, 15, 15, // 89 - 15, 15, 15, 15, 15, 15, 15, 15, // 89 - 15, 15, 15, 15, 15, 15, 15, 15, // 89 - 46, 15, 15, 15, 15, 15, 15, 15, // 89 - 15, 15, 15, 15, 15, 15, 15, 46, // 89 - 2, 3, 3, 3, 15, 59, 3, 120, // 90 - 5, 6, 5, 6, 5, 6, 5, 6, // 90 - 5, 6, 15, 15, 5, 6, 5, 6, // 90 - 5, 6, 5, 6, 8, 5, 6, 5, // 90 - 15, 121, 121, 121, 121, 121, 121, 121, // 90 - 121, 121, 60, 60, 60, 60, 60, 60, // 90 - 8, 59, 59, 59, 59, 59, 15, 15, // 90 - 46, 46, 46, 46, 46, 46, 46, 15, // 90 - 46, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 91 - 40, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 46, 46, 46, // 92 - 46, 60, 60, 59, 59, 59, 59, 46, // 92 - 46, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 40, 40, 40, // 92 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 40, 40, 40, 40, 40, // 93 - 40, 40, 40, 3, 59, 59, 59, 46, // 93 - 46, 46, 46, 46, 46, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 46, 46, 46, // 94 - 46, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 94 - 40, 40, 40, 40, 40, 40, 40, 40, // 95 - 40, 40, 40, 40, 40, 40, 40, 46, // 95 - 15, 15, 85, 85, 85, 85, 15, 15, // 95 - 15, 15, 15, 15, 15, 15, 15, 15, // 95 - 46, 46, 46, 46, 46, 46, 46, 46, // 95 - 46, 46, 46, 46, 46, 46, 46, 46, // 95 - 46, 46, 46, 46, 46, 46, 46, 46, // 95 - 46, 46, 46, 46, 46, 46, 46, 46, // 95 - 15, 15, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 15, 46, 46, 46, // 96 - 85, 85, 85, 85, 85, 85, 85, 85, // 96 - 85, 85, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 15, 15, 15, 15, // 96 - 15, 15, 15, 15, 46, 46, 46, 46, // 97 - 46, 46, 46, 46, 46, 46, 46, 46, // 97 - 46, 46, 46, 46, 46, 46, 46, 46, // 97 - 46, 46, 46, 46, 46, 46, 46, 46, // 97 - 15, 15, 15, 15, 15, 15, 15, 15, // 97 - 15, 15, 15, 15, 15, 15, 15, 15, // 97 - 15, 15, 15, 15, 15, 15, 15, 15, // 97 - 15, 15, 15, 15, 46, 46, 46, 15, // 97 - 114, 114, 114, 114, 114, 114, 114, 114, // 98 - 114, 114, 15, 15, 15, 15, 15, 15, // 98 - 15, 15, 15, 15, 15, 15, 15, 15, // 98 - 15, 15, 15, 15, 15, 15, 15, 15, // 98 - 15, 15, 15, 15, 15, 15, 15, 15, // 98 - 15, 15, 15, 15, 15, 15, 15, 15, // 98 - 15, 46, 46, 46, 46, 46, 46, 46, // 98 - 46, 46, 46, 46, 46, 46, 46, 46, // 98 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 46, 46, 46, 46, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 99 - 15, 15, 15, 15, 15, 15, 15, 46, // 99 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 46, // 100 - 46, 46, 46, 15, 15, 15, 15, 15, // 100 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 46, 46, // 101 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 15, 15, // 101 - 15, 15, 15, 15, 15, 15, 15, 46, // 101 - 40, 40, 40, 40, 40, 40, 40, 40, // 102 - 40, 40, 40, 40, 40, 40, 40, 40, // 102 - 40, 40, 40, 40, 40, 40, 40, 40, // 102 - 40, 40, 40, 40, 40, 40, 40, 40, // 102 - 40, 40, 40, 40, 40, 40, 46, 46, // 102 - 46, 46, 46, 46, 46, 46, 46, 46, // 102 - 46, 46, 46, 46, 46, 46, 46, 46, // 102 - 46, 46, 46, 46, 46, 46, 46, 46, // 102 - 40, 40, 40, 40, 40, 40, 40, 40, // 103 - 40, 40, 40, 40, 40, 40, 40, 40, // 103 - 40, 40, 40, 40, 40, 40, 40, 40, // 103 - 40, 40, 40, 40, 40, 40, 40, 40, // 103 - 40, 40, 40, 40, 46, 46, 46, 46, // 103 - 46, 46, 46, 46, 46, 46, 46, 46, // 103 - 46, 46, 46, 46, 46, 46, 46, 46, // 103 - 46, 46, 46, 46, 46, 46, 46, 46, // 103 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 122, 122, 122, 122, 122, 122, 122, 122, // 104 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 123, 123, 123, 123, 123, 123, 123, 123, // 105 - 40, 40, 40, 40, 40, 40, 40, 40, // 106 - 40, 40, 40, 40, 40, 40, 40, 40, // 106 - 40, 40, 40, 40, 40, 40, 40, 40, // 106 - 40, 40, 40, 40, 40, 40, 40, 40, // 106 - 40, 40, 40, 40, 40, 40, 40, 40, // 106 - 40, 40, 40, 40, 40, 40, 46, 46, // 106 - 46, 46, 46, 46, 46, 46, 46, 46, // 106 - 46, 46, 46, 46, 46, 46, 46, 46, // 106 - 16, 16, 16, 16, 16, 16, 16, 46, // 107 - 46, 46, 46, 46, 46, 46, 46, 46, // 107 - 46, 46, 46, 16, 16, 16, 16, 16, // 107 - 46, 46, 46, 46, 46, 46, 60, 40, // 107 - 40, 40, 40, 40, 40, 40, 40, 40, // 107 - 40, 7, 40, 40, 40, 40, 40, 40, // 107 - 40, 40, 40, 40, 40, 40, 40, 46, // 107 - 40, 40, 40, 40, 40, 46, 40, 46, // 107 - 40, 40, 46, 40, 40, 46, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 108 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 40, 40, 40, 40, 40, 40, // 109 - 40, 40, 46, 46, 46, 46, 46, 46, // 109 - 46, 46, 46, 46, 46, 46, 46, 46, // 109 - 46, 46, 46, 46, 46, 46, 46, 46, // 110 - 46, 46, 46, 46, 46, 46, 46, 46, // 110 - 46, 46, 46, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 110 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 40, 40, // 111 - 40, 40, 40, 40, 40, 40, 5, 6, // 111 - 46, 46, 46, 46, 46, 46, 46, 46, // 112 - 46, 46, 46, 46, 46, 46, 46, 46, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 112 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 46, 46, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 113 - 40, 40, 40, 40, 40, 40, 40, 40, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 114 - 40, 40, 40, 40, 40, 40, 40, 40, // 114 - 40, 40, 40, 40, 46, 46, 46, 46, // 114 - 46, 46, 46, 46, 46, 46, 46, 46, // 115 - 46, 46, 46, 46, 46, 46, 46, 46, // 115 - 46, 46, 46, 46, 46, 46, 46, 46, // 115 - 46, 46, 46, 46, 46, 46, 46, 46, // 115 - 60, 60, 60, 60, 46, 46, 46, 46, // 115 - 46, 46, 46, 46, 46, 46, 46, 46, // 115 - 3, 8, 8, 12, 12, 5, 6, 5, // 115 - 6, 5, 6, 5, 6, 5, 6, 5, // 115 - 6, 5, 6, 5, 6, 46, 46, 46, // 116 - 46, 3, 3, 3, 3, 12, 12, 12, // 116 - 3, 3, 3, 46, 3, 3, 3, 3, // 116 - 8, 5, 6, 5, 6, 5, 6, 3, // 116 - 3, 3, 7, 8, 7, 7, 7, 46, // 116 - 3, 4, 3, 3, 46, 46, 46, 46, // 116 - 40, 40, 40, 46, 40, 46, 40, 40, // 116 - 40, 40, 40, 40, 40, 40, 40, 40, // 116 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 40, 40, 40, // 117 - 40, 40, 40, 40, 40, 46, 46, 104, // 117 - 46, 3, 3, 3, 4, 3, 3, 3, // 118 - 5, 6, 3, 7, 3, 8, 3, 3, // 118 - 9, 9, 9, 9, 9, 9, 9, 9, // 118 - 9, 9, 3, 3, 7, 7, 7, 3, // 118 - 3, 10, 10, 10, 10, 10, 10, 10, // 118 - 10, 10, 10, 10, 10, 10, 10, 10, // 118 - 10, 10, 10, 10, 10, 10, 10, 10, // 118 - 10, 10, 10, 5, 3, 6, 11, 12, // 118 - 11, 13, 13, 13, 13, 13, 13, 13, // 119 - 13, 13, 13, 13, 13, 13, 13, 13, // 119 - 13, 13, 13, 13, 13, 13, 13, 13, // 119 - 13, 13, 13, 5, 7, 6, 7, 46, // 119 - 46, 3, 5, 6, 3, 3, 40, 40, // 119 - 40, 40, 40, 40, 40, 40, 40, 40, // 119 - 59, 40, 40, 40, 40, 40, 40, 40, // 119 - 40, 40, 40, 40, 40, 40, 40, 40, // 119 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 59, 59, // 120 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 40, 40, // 120 - 40, 40, 40, 40, 40, 40, 40, 46, // 120 - 46, 46, 40, 40, 40, 40, 40, 40, // 121 - 46, 46, 40, 40, 40, 40, 40, 40, // 121 - 46, 46, 40, 40, 40, 40, 40, 40, // 121 - 46, 46, 40, 40, 40, 46, 46, 46, // 121 - 4, 4, 7, 11, 15, 4, 4, 46, // 121 - 7, 7, 7, 7, 7, 15, 15, 46, // 121 - 46, 46, 46, 46, 46, 46, 46, 46, // 121 - 46, 46, 46, 46, 46, 15, 46, 46 // 121 -}; - - -// The A table has 124 entries for a total of 496 bytes. -const uint32 JS::CharInfo::a[] = { - 0x0000000F, // 0 Cc - 0x0004000F, // 1 Cc, whitespace - 0x0004000C, // 2 Zs, whitespace - 0x00000018, // 3 Po - 0x0002001A, // 4 Sc, currency - 0x00000015, // 5 Ps - 0x00000016, // 6 Pe - 0x00000019, // 7 Sm - 0x00000014, // 8 Pd - 0x00036009, // 9 Nd, identifier part, decimal 16 - 0x0822FE01, // 10 Lu, hasLower (add 32), identifier start, supradecimal 31 - 0x0000001B, // 11 Sk - 0x00020017, // 12 Pc, underscore - 0x0812FE02, // 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 - 0x0005000F, // 14 Cc, break - 0x0000001C, // 15 So - 0x00020002, // 16 Ll, identifier start - 0x0000600B, // 17 No, decimal 16 - 0x0000500B, // 18 No, decimal 8 - 0x0000800B, // 19 No, strange - 0x08220001, // 20 Lu, hasLower (add 32), identifier start - 0x08120002, // 21 Ll, hasUpper (subtract 32), identifier start - 0xE1D20002, // 22 Ll, hasUpper (subtract -121), identifier start - 0x00620001, // 23 Lu, hasLower (add 1), identifier start - 0x00520002, // 24 Ll, hasUpper (subtract 1), identifier start - 0xCE620001, // 25 Lu, hasLower (add -199), identifier start - 0x3A120002, // 26 Ll, hasUpper (subtract 232), identifier start - 0xE1E20001, // 27 Lu, hasLower (add -121), identifier start - 0x4B120002, // 28 Ll, hasUpper (subtract 300), identifier start - 0x34A20001, // 29 Lu, hasLower (add 210), identifier start - 0x33A20001, // 30 Lu, hasLower (add 206), identifier start - 0x33620001, // 31 Lu, hasLower (add 205), identifier start - 0x32A20001, // 32 Lu, hasLower (add 202), identifier start - 0x32E20001, // 33 Lu, hasLower (add 203), identifier start - 0x33E20001, // 34 Lu, hasLower (add 207), identifier start - 0x34E20001, // 35 Lu, hasLower (add 211), identifier start - 0x34620001, // 36 Lu, hasLower (add 209), identifier start - 0x35620001, // 37 Lu, hasLower (add 213), identifier start - 0x00020001, // 38 Lu, identifier start - 0x36A20001, // 39 Lu, hasLower (add 218), identifier start - 0x00020005, // 40 Lo, identifier start - 0x36620001, // 41 Lu, hasLower (add 217), identifier start - 0x36E20001, // 42 Lu, hasLower (add 219), identifier start - 0x00AA0001, // 43 Lu, hasLower (add 2), hasTitle, identifier start - 0x007A0003, // 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start - 0x009A0002, // 45 Ll, hasUpper (subtract 2), hasTitle, identifier start - 0x00000000, // 46 unassigned - 0x34920002, // 47 Ll, hasUpper (subtract 210), identifier start - 0x33920002, // 48 Ll, hasUpper (subtract 206), identifier start - 0x33520002, // 49 Ll, hasUpper (subtract 205), identifier start - 0x32920002, // 50 Ll, hasUpper (subtract 202), identifier start - 0x32D20002, // 51 Ll, hasUpper (subtract 203), identifier start - 0x33D20002, // 52 Ll, hasUpper (subtract 207), identifier start - 0x34520002, // 53 Ll, hasUpper (subtract 209), identifier start - 0x34D20002, // 54 Ll, hasUpper (subtract 211), identifier start - 0x35520002, // 55 Ll, hasUpper (subtract 213), identifier start - 0x36920002, // 56 Ll, hasUpper (subtract 218), identifier start - 0x36520002, // 57 Ll, hasUpper (subtract 217), identifier start - 0x36D20002, // 58 Ll, hasUpper (subtract 219), identifier start - 0x00020004, // 59 Lm, identifier start - 0x00030006, // 60 Mn, identifier part - 0x09A20001, // 61 Lu, hasLower (add 38), identifier start - 0x09620001, // 62 Lu, hasLower (add 37), identifier start - 0x10220001, // 63 Lu, hasLower (add 64), identifier start - 0x0FE20001, // 64 Lu, hasLower (add 63), identifier start - 0x09920002, // 65 Ll, hasUpper (subtract 38), identifier start - 0x09520002, // 66 Ll, hasUpper (subtract 37), identifier start - 0x10120002, // 67 Ll, hasUpper (subtract 64), identifier start - 0x0FD20002, // 68 Ll, hasUpper (subtract 63), identifier start - 0x0F920002, // 69 Ll, hasUpper (subtract 62), identifier start - 0x0E520002, // 70 Ll, hasUpper (subtract 57), identifier start - 0x0BD20002, // 71 Ll, hasUpper (subtract 47), identifier start - 0x0D920002, // 72 Ll, hasUpper (subtract 54), identifier start - 0x15920002, // 73 Ll, hasUpper (subtract 86), identifier start - 0x14120002, // 74 Ll, hasUpper (subtract 80), identifier start - 0x14220001, // 75 Lu, hasLower (add 80), identifier start - 0x0C220001, // 76 Lu, hasLower (add 48), identifier start - 0x0C120002, // 77 Ll, hasUpper (subtract 48), identifier start - 0x00034009, // 78 Nd, identifier part, decimal 0 - 0x00000007, // 79 Me - 0x00030008, // 80 Mc, identifier part - 0x00037409, // 81 Nd, identifier part, decimal 26 - 0x00005A0B, // 82 No, decimal 13 - 0x00006E0B, // 83 No, decimal 23 - 0x0000740B, // 84 No, decimal 26 - 0x0000000B, // 85 No - 0xFE120002, // 86 Ll, hasUpper (subtract -8), identifier start - 0xFE220001, // 87 Lu, hasLower (add -8), identifier start - 0xED920002, // 88 Ll, hasUpper (subtract -74), identifier start - 0xEA920002, // 89 Ll, hasUpper (subtract -86), identifier start - 0xE7120002, // 90 Ll, hasUpper (subtract -100), identifier start - 0xE0120002, // 91 Ll, hasUpper (subtract -128), identifier start - 0xE4120002, // 92 Ll, hasUpper (subtract -112), identifier start - 0xE0920002, // 93 Ll, hasUpper (subtract -126), identifier start - 0xFDD20002, // 94 Ll, hasUpper (subtract -9), identifier start - 0xEDA20001, // 95 Lu, hasLower (add -74), identifier start - 0xFDE20001, // 96 Lu, hasLower (add -9), identifier start - 0xEAA20001, // 97 Lu, hasLower (add -86), identifier start - 0xE7220001, // 98 Lu, hasLower (add -100), identifier start - 0xFE520002, // 99 Ll, hasUpper (subtract -7), identifier start - 0xE4220001, // 100 Lu, hasLower (add -112), identifier start - 0xFE620001, // 101 Lu, hasLower (add -7), identifier start - 0xE0220001, // 102 Lu, hasLower (add -128), identifier start - 0xE0A20001, // 103 Lu, hasLower (add -126), identifier start - 0x00010010, // 104 Cf, ignorable - 0x0005000D, // 105 Zl, break - 0x0005000E, // 106 Zp, break - 0x0000400B, // 107 No, decimal 0 - 0x0000440B, // 108 No, decimal 2 - 0x0422420A, // 109 Nl, hasLower (add 16), identifier start, decimal 1 - 0x0422800A, // 110 Nl, hasLower (add 16), identifier start, strange - 0x0412620A, // 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 - 0x0412800A, // 112 Nl, hasUpper (subtract 16), identifier start, strange - 0x0002800A, // 113 Nl, identifier start, strange - 0x0000420B, // 114 No, decimal 1 - 0x0000720B, // 115 No, decimal 25 - 0x06A0001C, // 116 So, hasLower (add 26) - 0x0690001C, // 117 So, hasUpper (subtract 26) - 0x00006C0B, // 118 No, decimal 22 - 0x0000560B, // 119 No, decimal 11 - 0x0002720A, // 120 Nl, identifier start, decimal 25 - 0x0002400A, // 121 Nl, identifier start, decimal 0 - 0x00000013, // 122 Cs - 0x00000012 // 123 Co -}; - - -// Return c converted to upper case. If c cannot be converted to upper case, -// return c unchanged. -char16 JS::toUpper(char16 c) -{ - CharInfo ci(c); - if (ci.info & 0x00100000) - c = static_cast(static_cast(c) - (static_cast(ci.info) >> 22)); - return c; -} - - -// Return c converted to lower case. If c cannot be converted to lower case, -// return c unchanged. -char16 JS::toLower(char16 c) -{ - CharInfo ci(c); - if (ci.info & 0x00200000) - c = static_cast(static_cast(c) + (static_cast(ci.info) >> 22)); - return c; -} - - -// Return true if c is an ASCII hexadecimal digit, in which case store the digit's numeric value in d. -bool JS::isASCIIHexDigit(char16 c, uint &digit) -{ - uint cv = c; - - if (cv < '0') - return false; - if (cv <= '9') { - digit = cv - '0'; - return true; - } - cv |= 0x20; - if (cv >= 'a' && cv <= 'f') { - digit = cv - 'a' + 10; - return true; - } - return false; -} - - -// Return str advanced past white space characters, but no further than strEnd. -const char16 *JS::skipWhiteSpace(const char16 *str, const char16 *strEnd) -{ - while (str != strEnd && isSpace(*str)) - str++; - return str; -} - - -// -// Zones -// - -// #define DEBUG_ZONE to allocate each object in its own malloc block. -// This allows tools such as Purify to do bounds checking on all blocks. - - -// Construct a Zone that allocates memory in chunks of the given size. -JS::Zone::Zone(size_t blockSize): headers(0), freeBegin(0), freeEnd(0), blockSize(blockSize) -{ - ASSERT(blockSize && !(blockSize & basicAlignment-1)); -} - - -// Deallocate the Zone's blocks. -void JS::Zone::clear() -{ - Header *h = headers; - while (h) { - Header *next = h->next; - STD::free(h); - h = next; - } - headers = 0; -} - - -// Allocate a fully aligned block of the given size. -// Throw bad_alloc if out of memory, without corrupting any of the Zone data structures. -void *JS::Zone::newBlock(size_t size) -{ - Header *h = static_cast
(STD::malloc(sizeof(Header) + size)); - h->next = headers; - headers = h; - return h+1; -} - - -// Allocate a naturally-aligned object of the given size (in bytes). Throw -// bad_alloc if out of memory, without corrupting any of the Zone data structures. -void *JS::Zone::allocate(size_t size) -{ - ASSERT(size); // Can't allocate zero-size blocks. - #ifdef DEBUG_ZONE - return newBlock(size); -#else - size = size + (basicAlignment-1) & -basicAlignment; // Round up to natural alignment if necessary - char *p = freeBegin; - size_t freeBytes = static_cast(freeEnd - p); - - if (size > freeBytes) { - // If freeBytes is at least a quarter of blockSize, allocate a separate block. - if (freeBytes<<2 >= blockSize || size >= blockSize) - return newBlock(size); - - p = static_cast(newBlock(blockSize)); - freeEnd = p + blockSize; - } - freeBegin = p + size; - return p; -#endif -} - - -// Same as allocate but does not align size up to basicAlignment. Thus, the next -// object allocated in the zone will immediately follow this one if it falls in the same zone block. -// Use this when all objects in the zone have the same size. -void *JS::Zone::allocateUnaligned(size_t size) -{ - ASSERT(size); // Can't allocate zero-size blocks. - #ifdef DEBUG_ZONE - return newBlock(size); - #else - char *p = freeBegin; - size_t freeBytes = static_cast(freeEnd - p); - - if (size > freeBytes) { - // If freeBytes is at least a quarter of blockSize, allocate a separate block. - if (freeBytes<<2 >= blockSize || size >= blockSize) - return newBlock(size); - - p = static_cast(newBlock(blockSize)); - freeEnd = p + blockSize; - } - freeBegin = p + size; - return p; - #endif -} - - -// -// Arenas -// - -struct JS::Arena::DestructorEntry: JS::ArenaObject { - DestructorEntry *next; // Next destructor registration in linked list - void (*destructor)(void *); // Destructor function - void *object; // Object on which to call the destructor - - DestructorEntry(void (*destructor)(void *), void *object): destructor(destructor), object(object) {} -}; - - -// Call the Arena's registered destructors. -void JS::Arena::runDestructors() -{ - DestructorEntry *e = destructorEntries; - while (e) { - e->destructor(e->object); - e = e->next; - } - destructorEntries = 0; -} - - -// Ensure that object's destructor is called at the time the arena is deallocated or cleared. -// The destructors will be called in reverse order of being registered. -// registerDestructor might itself runs out of memory, in which case it immediately -// calls object's destructor before throwing bad_alloc. -void JS::Arena::newDestructorEntry(void (*destructor)(void *), void *object) -{ - try { - DestructorEntry *e = new(*this) DestructorEntry(destructor, object); - e->next = destructorEntries; - destructorEntries = e; - } catch (...) { - destructor(object); - throw; - } -} - - -// Allocate a String in the Arena and register that String so that it is deallocated at -// the same time as the Arena. -// DO NOT CALL DELETE ON THE RESULT! -JS::String &JS::newArenaString(Arena &arena) -{ - String *s = new(arena) String(); - arena.registerDestructor(s); - return *s; -} - -JS::String &JS::newArenaString(Arena &arena, const String &str) -{ - String *s = new(arena) String(str); - arena.registerDestructor(s); - return *s; -} - - -// -// Input -// - - -// Read a line from the input file, including the trailing line break character. -// Return the total number of characters read, which is str's length. -// Translate and sequences to characters; a sequence -// only counts as one character. -size_t JS::LineReader::readLine(string &str) -{ - int ch; - bool oldCRWasLast = crWasLast; - crWasLast = false; - - str.resize(0); - while ((ch = getc(in)) != EOF) { - if (ch == '\n') { - if (!str.size() && oldCRWasLast) - continue; - str += '\n'; - break; - } - if (ch == '\r') { - crWasLast = true; - str += '\n'; - break; - } - str += static_cast(ch); - } - - return str.size(); -} - - -size_t JS::LineReader::readLine(String &wstr) -{ - string str; - size_t n = readLine(str); - wstr.resize(n); - std::transform(str.begin(), str.end(), wstr.begin(), widen); - return n; -} - - -// -// Output -// - -#ifdef XP_MAC_MPW -// Macintosh MPW replacements for the ANSI routines. These translate LF's to CR's because -// the MPW libraries supplied by Metrowerks don't do that for some reason. -static void translateLFtoCR(char *begin, char *end) -{ - while (begin != end) { - if (*begin == '\n') - *begin = '\r'; - ++begin; - } -} - -size_t JS::printChars(FILE *file, const char *begin, const char *end) -{ - ASSERT(end >= begin); - size_t n = static_cast(end - begin); - size_t extra = 0; - char buffer[1024]; - - while (n > sizeof buffer) { - std::memcpy(buffer, begin, sizeof buffer); - translateLFtoCR(buffer, buffer + sizeof buffer); - extra += fwrite(buffer, 1, sizeof buffer, file); - n -= sizeof buffer; - begin += sizeof buffer; - } - std::memcpy(buffer, begin, n); - translateLFtoCR(buffer, buffer + n); - return extra + fwrite(buffer, 1, n, file); -} - -int std::fputc(int c, FILE *file) -{ - char buffer = static_cast(c); - if (buffer == '\n') - buffer = '\r'; - return static_cast(fwrite(&buffer, 1, 1, file)); -} - -int std::fputs(const char *s, FILE *file) -{ - return static_cast(JS::printChars(file, s, s + strlen(s))); -} - -int std::fprintf(FILE* file, const char *format, ...) -{ - JS::Buffer b; - - while (true) { - va_list args; - va_start(args, format); - int n = vsnprintf(b.buffer, b.size, format, args); - va_end(args); - if (n >= 0 && n < b.size) { - translateLFtoCR(b.buffer, b.buffer + n); - return static_cast(fwrite(b.buffer, 1, static_cast(n), file)); - } - b.expand(b.size*2); - } -} -#endif // XP_MAC_MPW - - - -// Write ch. -void JS::Formatter::printChar8(char ch) -{ - printStr8(&ch, &ch + 1); -} - - -// Write ch. -void JS::Formatter::printChar16(char16 ch) -{ - printStr16(&ch, &ch + 1); -} - - -// Write the null-terminated string str. -void JS::Formatter::printZStr8(const char *str) -{ - printStr8(str, str + strlen(str)); -} - - -// Write the String s. -void JS::Formatter::printString16(const String &s) -{ - const char16 *begin = s.data(); - printStr16(begin, begin + s.size()); -} - - -// Write the printf format using the supplied args. -void JS::Formatter::printVFormat8(const char *format, va_list args) -{ - Buffer b; - - while (true) { - int n = vsnprintf(b.buffer, b.size, format, args); - if (n >= 0 && static_cast(n) < b.size) { - printStr8(b.buffer, b.buffer + n); - return; - } - b.expand(b.size*2); - } -} - - -static const int printCharBufferSize = 64; - -// Print ch count times. -void JS::printChar(Formatter &f, char ch, int count) -{ - char str[printCharBufferSize]; - - while (count > 0) { - int c = count; - if (c > printCharBufferSize) - c = printCharBufferSize; - count -= c; - STD::memset(str, ch, static_cast(c)); - printString(f, str, str+c); - } -} - - -// Print ch count times. -void JS::printChar(Formatter &f, char16 ch, int count) -{ - char16 str[printCharBufferSize]; - - while (count > 0) { - int c = count; - if (c > printCharBufferSize) - c = printCharBufferSize; - count -= c; - char16 *strEnd = str + c; - std::fill(str, strEnd, ch); - printString(f, str, strEnd); - } -} - - -// Print i using the given formatting string, padding on the left with pad characters -// to use at least nDigits characters. -void JS::printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format) -{ - char str[20]; - int n = sprintf(str, format, i); - if (n < nDigits) - printChar(f, pad, nDigits - n); - printString(f, str, str+n); -} - - -// Print p as a pointer. -void JS::printPtr(Formatter &f, void *p) -{ - char str[20]; - int n = sprintf(str, "%p", p); - printString(f, str, str+n); -} - - -// printf formats for printing non-ASCII characters on an ASCII stream -#ifdef XP_MAC - static const char unprintableFormat[] = "\xC7%.4X\xC8"; // Use angle quotes -#elif defined _WIN32 - static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes -#else - static const char unprintableFormat[] = "<%.4X>"; -#endif - - -static const uint16 defaultFilterRanges[] = { - 0x00, 0x09, // Filter all control characters except \t and \n - 0x0B, 0x20, - 0x7F, 0x100, // Filter all non-ASCII characters - 0, 0 -}; - -JS::BitSet<256> JS::AsciiFileFormatter::defaultFilter(defaultFilterRanges); - - -// Construct an AsciiFileFormatter using the given file and filter f. -// If f is nil, use the default filter. -JS::AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *f): - file(file) - #ifndef _WIN32 // Microsoft Visual C++ 6.0 bug - , filter(f ? *f : defaultFilter) - #endif -{ - #ifdef _WIN32 // Microsoft Visual C++ 6.0 bug - if (f) - filter = *f; - else - filter = defaultFilter; - #endif - filterEmpty = filter.none(); -} - - -// Write ch, escaping non-ASCII characters. -void JS::AsciiFileFormatter::printChar8(char ch) -{ - if (filterChar(ch)) - fprintf(file, unprintableFormat, static_cast(ch)); - else - fputc(ch, file); -} - - -// Write ch, escaping non-ASCII characters. -void JS::AsciiFileFormatter::printChar16(char16 ch) -{ - if (filterChar(ch)) - fprintf(file, unprintableFormat, char16Value(ch)); - else - fputc(static_cast(ch), file); -} - - -// Write the null-terminated string str, escaping non-ASCII characters. -void JS::AsciiFileFormatter::printZStr8(const char *str) -{ - if (filterEmpty) - fputs(str, file); - else - printStr8(str, str + strlen(str)); -} - - -// Write the string between strBegin and strEnd, escaping non-ASCII characters. -void JS::AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd) -{ - if (filterEmpty) - printChars(file, strBegin, strEnd); - else { - ASSERT(strEnd >= strBegin); - const char *p = strBegin; - while (strBegin != strEnd) { - char ch = *strBegin; - if (filterChar(ch)) { - if (p != strBegin) { - printChars(file, p, strBegin); - p = strBegin; - } - fprintf(file, unprintableFormat, static_cast(ch)); - } - ++strBegin; - } - if (p != strBegin) - printChars(file, p, strBegin); - } -} - - -// Write the string between strBegin and strEnd, escaping non-ASCII characters. -void JS::AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) -{ - char buffer[512]; - - ASSERT(strEnd >= strBegin); - char *q = buffer; - while (strBegin != strEnd) { - char16 ch = *strBegin++; - if (filterChar(ch)) { - if (q != buffer) { - printChars(file, buffer, q); - q = buffer; - } - fprintf(file, unprintableFormat, char16Value(ch)); - } else { - *q++ = static_cast(ch); - if (q == buffer + sizeof buffer) { - printChars(file, buffer, buffer + sizeof buffer); - q = buffer; - } - } - } - if (q != buffer) - printChars(file, buffer, q); -} - -JS::AsciiFileFormatter JS::stdOut(stdout); -JS::AsciiFileFormatter JS::stdErr(stderr); - - -// Write ch. -void JS::StringFormatter::printChar8(char ch) -{ - s += ch; -} - - -// Write ch. -void JS::StringFormatter::printChar16(char16 ch) -{ - s += ch; -} - - -// Write the null-terminated string str. -void JS::StringFormatter::printZStr8(const char *str) -{ - s += str; -} - - -// Write the string between strBegin and strEnd. -void JS::StringFormatter::printStr8(const char *strBegin, const char *strEnd) -{ - appendChars(s, strBegin, strEnd); -} - - -// Write the string between strBegin and strEnd. -void JS::StringFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) -{ - s.append(strBegin, strEnd); -} - - -// Write the String str. -void JS::StringFormatter::printString16(const String &str) -{ - s += str; -} - - -// -// Formatted Output -// - -// See "Prettyprinting" by Derek Oppen in ACM Transactions on Programming Languages and Systems 2:4, -// October 1980, pages 477-482 for the algorithm. - - -// The default line width for pretty printing -uint32 JS::PrettyPrinter::defaultLineWidth = 20; - - -// Create a PrettyPrinter that outputs to Formatter f. The PrettyPrinter breaks lines at -// optional breaks so as to try not to exceed lines of width lineWidth, although it may not -// always be able to do so. Formatter f should be at the beginning of a line. -// Call end before destroying the Formatter; otherwise the last line may not be output to f. -JS::PrettyPrinter::PrettyPrinter(Formatter &f, uint32 lineWidth): - lineWidth(min(lineWidth, unlimitedLineWidth)), - outputFormatter(f), - outputPos(0), - lineNum(0), - lastBreak(0), - margin(0), - nNestedBlocks(0), - leftSerialPos(0), - rightSerialPos(0), - itemPool(20) -{ - #ifdef DEBUG - topRegion = 0; - #endif -} - - -// Destroy the PrettyPrinter. Because it's a very bad idea for a destructor to throw -// exceptions, this destructor does not flush any buffered output. Call end just before -// destroying the PrettyPrinter to do that. -JS::PrettyPrinter::~PrettyPrinter() -{ - ASSERT(!topRegion && !nNestedBlocks); -} - - -// Output either a line break (if sameLine is false) or length spaces (if sameLine is true). -// Also advance leftSerialPos by length. -// -// If this method throws an exception, it is guaranteed to already have updated all of the -// PrettyPrinter state; all that might be missing would be some output to outputFormatter. -void JS::PrettyPrinter::outputBreak(bool sameLine, uint32 length) -{ - leftSerialPos += length; - - if (sameLine) { - outputPos += length; - // Exceptions may be thrown below. - printChar(outputFormatter, ' ', static_cast(length)); - } else { - lastBreak = ++lineNum; - outputPos = margin; - // Exceptions may be thrown below. - outputFormatter << '\n'; - printChar(outputFormatter, ' ', static_cast(margin)); - } -} - - -// Check to see whether (rightSerialPos+rightOffset)-leftSerialPos has gotten so large that we may pop items -// off the left end of activeItems because their totalLengths are known to be larger than the -// amount of space left on the current line. -// Return true if there are any items left on activeItems. -// -// If this method throws an exception, it leaves the PrettyPrinter in a consistent state, having -// atomically popped off one or more items from the left end of activeItems. -bool JS::PrettyPrinter::reduceLeftActiveItems(uint32 rightOffset) -{ - uint32 newRightSerialPos = rightSerialPos + rightOffset; - while (activeItems) { - Item *leftItem = &activeItems.front(); - if (itemStack && leftItem == itemStack.front()) { - if (outputPos + newRightSerialPos - leftSerialPos > lineWidth) { - itemStack.pop_front(); - leftItem->lengthKnown = true; - leftItem->totalLength = infiniteLength; - } else if (leftItem->lengthKnown) - itemStack.pop_front(); - } - - if (!leftItem->lengthKnown) - return true; - - activeItems.pop_front(); - try { - uint32 length = leftItem->length; - switch (leftItem->kind) { - case Item::text: - { - outputPos += length; - leftSerialPos += length; - // Exceptions may be thrown below. - char16 *textBegin; - char16 *textEnd; - do { - length -= itemText.pop_front(length, textBegin, textEnd); - printString(outputFormatter, textBegin, textEnd); - } while (length); - } - break; - - case Item::blockBegin: - case Item::indentBlockBegin: - { - BlockInfo *b = savedBlocks.advance_back(); - b->margin = margin; - b->lastBreak = lastBreak; - b->fits = outputPos + leftItem->totalLength <= lineWidth; - if (leftItem->hasKind(Item::blockBegin)) - margin = outputPos; - else - margin += length; - } - break; - - case Item::blockEnd: - { - BlockInfo &b = savedBlocks.pop_back(); - margin = b.margin; - lastBreak = b.lastBreak; - } - break; - - case Item::indent: - margin += length; - ASSERT(static_cast(margin) >= 0); - break; - - case Item::linearBreak: - // Exceptions may be thrown below, but only after updating the PrettyPrinter. - outputBreak(savedBlocks.back().fits, length); - break; - - case Item::fillBreak: - // Exceptions may be thrown below, but only after updating the PrettyPrinter. - outputBreak(lastBreak == lineNum && outputPos + leftItem->totalLength <= lineWidth, length); - break; - } - } catch (...) { - itemPool.destroy(leftItem); - throw; - } - itemPool.destroy(leftItem); - } - return false; -} - - -// A break or end of input is about to be processed. Check whether there are any complete -// blocks or clumps on the itemStack whose lengths we can now compute; if so, compute these -// and pop them off the itemStack. -// The current rightSerialPos must be the beginning of the break or end of input. -// -// This method can't throw exceptions. -void JS::PrettyPrinter::reduceRightActiveItems() -{ - uint32 nUnmatchedBlockEnds = 0; - while (itemStack) { - Item *rightItem = itemStack.pop_back(); - switch (rightItem->kind) { - case Item::blockBegin: - case Item::indentBlockBegin: - if (!nUnmatchedBlockEnds) { - itemStack.fast_push_back(rightItem); - return; - } - rightItem->computeTotalLength(rightSerialPos); - --nUnmatchedBlockEnds; - break; - - case Item::blockEnd: - ++nUnmatchedBlockEnds; - break; - - case Item::linearBreak: - case Item::fillBreak: - rightItem->computeTotalLength(rightSerialPos); - if (!nUnmatchedBlockEnds) - return; // There can be at most one consecutive break posted on the itemStack. - break; - - default: - ASSERT(false); // Other kinds can't be pushed onto the itemStack. - } - } -} - - -// Indent the beginning of every new line after this one by offset until the corresponding endIndent -// call. Return an Item to pass to endIndent that will end this indentation. -// This method may throw an exception, in which case the PrettyPrinter is left unchanged. -JS::PrettyPrinter::Item &JS::PrettyPrinter::beginIndent(int32 offset) -{ - Item *unindent = new(itemPool) Item(Item::indent, static_cast(-offset)); - if (activeItems) { - try { - activeItems.push_back(*new(itemPool) Item(Item::indent, static_cast(offset))); - } catch (...) { - itemPool.destroy(unindent); - throw; - } - } else { - margin += offset; - ASSERT(static_cast(margin) >= 0); - } - return *unindent; -} - - -// End an indent began by beginIndent. i should be the result of a beginIndent. -// This method can't throw exceptions (it's called by the Indent destructor). -void JS::PrettyPrinter::endIndent(Item &i) -{ - if (activeItems) - activeItems.push_back(i); - else { - margin += i.length; - ASSERT(static_cast(margin) >= 0); - itemPool.destroy(&i); - } -} - - -// Begin a logical block. If kind is Item::indentBlockBegin, offset is the indent to use for -// the second and subsequent lines of this block. -// Return an Item to pass to endBlock that will end this block. -// This method may throw an exception, in which case the PrettyPrinter is left unchanged. -JS::PrettyPrinter::Item &JS::PrettyPrinter::beginBlock(Item::Kind kind, int32 offset) -{ - uint32 newNNestedBlocks = nNestedBlocks + 1; - savedBlocks.reserve(newNNestedBlocks); - itemStack.reserve_back(1 + newNNestedBlocks); - Item *endItem = new(itemPool) Item(Item::blockEnd); - Item *beginItem; - try { - beginItem = new(itemPool) Item(kind, static_cast(offset), rightSerialPos); - } catch (...) { - itemPool.destroy(endItem); - throw; - } - // No state modifications before this point. - // No exceptions after this point. - activeItems.push_back(*beginItem); - itemStack.fast_push_back(beginItem); - nNestedBlocks = newNNestedBlocks; - return *endItem; -} - - -// End a logical block began by beginBlock. i should be the result of a beginBlock. -// This method can't throw exceptions (it's called by the Block destructor). -void JS::PrettyPrinter::endBlock(Item &i) -{ - activeItems.push_back(i); - itemStack.fast_push_back(&i); - --nNestedBlocks; -} - - -// Write a conditional line break. This kind of a line break can only be emitted inside a block. -// -// A linear line break starts a new line if the containing block cannot be put all one one line; -// otherwise the line break is replaced by nSpaces spaces. -// Typically a block contains several linear breaks; either they all start new lines or none of them do. -// Moreover, if a block directly contains a required break then linear breaks become required breaks. -// -// A fill line break starts a new line if either the preceding clump or the following clump cannot -// be placed entirely on one line or if the following clump would not fit on the current line. A -// clump is a consecutive sequence of strings and nested blocks delimited by either a break or the -// beginning or end of the currently enclosing block. -// -// If this method throws an exception, it leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind) -{ - ASSERT(nSpaces <= unlimitedLineWidth && nNestedBlocks); - reduceRightActiveItems(); - itemStack.reserve_back(1 + nNestedBlocks); - // Begin of exception-atomic stack update. Only new(itemPool) can throw an exception here, - // in which case nothing is updated. - Item *i = new(itemPool) Item(kind, nSpaces, rightSerialPos); - activeItems.push_back(*i); - itemStack.fast_push_back(i); - rightSerialPos += nSpaces; - // End of exception-atomic stack update. - reduceLeftActiveItems(0); -} - - -// Write the string between strBegin and strEnd. Any embedded newlines ('\n' only) -// become required line breaks. -// -// If this method throws an exception, it may have partially formatted the string but -// leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::printStr8(const char *strBegin, const char *strEnd) -{ - while (strBegin != strEnd) { - const char *sectionEnd = findValue(strBegin, strEnd, '\n'); - uint32 sectionLength = static_cast(sectionEnd - strBegin); - if (sectionLength) { - if (reduceLeftActiveItems(sectionLength)) { - itemText.reserve_back(sectionLength); - Item &backItem = activeItems.back(); - // Begin of exception-atomic update. Only new(itemPool) - // can throw an exception here, in which case nothing is updated. - if (backItem.hasKind(Item::text)) - backItem.length += sectionLength; - else - activeItems.push_back(*new(itemPool) Item(Item::text, sectionLength)); - rightSerialPos += sectionLength; - itemText.fast_append(reinterpret_cast(strBegin), reinterpret_cast(sectionEnd)); - // End of exception-atomic update. - } else { - ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos); - outputPos += sectionLength; - printString(outputFormatter, strBegin, sectionEnd); - } - strBegin = sectionEnd; - if (strBegin == strEnd) - break; - } - requiredBreak(); - ++strBegin; - } -} - - -// Write the string between strBegin and strEnd. Any embedded newlines ('\n' only) -// become required line breaks. -// -// If this method throws an exception, it may have partially formatted the string but -// leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::printStr16(const char16 *strBegin, const char16 *strEnd) -{ - while (strBegin != strEnd) { - const char16 *sectionEnd = findValue(strBegin, strEnd, uni::lf); - uint32 sectionLength = static_cast(sectionEnd - strBegin); - if (sectionLength) { - if (reduceLeftActiveItems(sectionLength)) { - itemText.reserve_back(sectionLength); - Item &backItem = activeItems.back(); - // Begin of exception-atomic update. Only new(itemPool) - // can throw an exception here, in which case nothing is updated. - if (backItem.hasKind(Item::text)) - backItem.length += sectionLength; - else - activeItems.push_back(*new(itemPool) Item(Item::text, sectionLength)); - rightSerialPos += sectionLength; - itemText.fast_append(strBegin, sectionEnd); - // End of exception-atomic update. - } else { - ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos); - outputPos += sectionLength; - printString(outputFormatter, strBegin, sectionEnd); - } - strBegin = sectionEnd; - if (strBegin == strEnd) - break; - } - requiredBreak(); - ++strBegin; - } -} - - -// Write a required line break. -// -// If this method throws an exception, it may have emitted partial output but -// leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::requiredBreak() -{ - reduceRightActiveItems(); - reduceLeftActiveItems(infiniteLength); - ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos); - outputBreak(false, 0); -} - - -// If required is true, write a required line break; otherwise write a linear line break -// of the given width. -// -// If this method throws an exception, it may have emitted partial output but -// leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::linearBreak(uint32 nSpaces, bool required) -{ - if (required) - requiredBreak(); - else - linearBreak(nSpaces); -} - - -// Flush any saved output in the PrettyPrinter to the output. Call this just before -// destroying the PrettyPrinter. All Indent and Block objects must have been exited already. -// -// If this method throws an exception, it may have emitted partial output but -// leaves the PrettyPrinter in a consistent state. -void JS::PrettyPrinter::end() -{ - ASSERT(!topRegion); - reduceRightActiveItems(); - reduceLeftActiveItems(infiniteLength); - ASSERT(!savedBlocks && !itemStack && !activeItems && !itemText && rightSerialPos == leftSerialPos && !margin); -} - - -// -// Exceptions -// - - -static const char *const kindStrings[] = { - "Syntax error", // syntaxError - "Stack overflow" // stackOverflow -}; - -// Return a null-terminated string describing the exception's kind. -const char *JS::Exception::kindString() const -{ - return kindStrings[kind]; -} - - -// Return the full error message. -JS::String JS::Exception::fullMessage() const -{ - String m(widenCString("In ")); - m += sourceFile; - if (lineNum) { - char b[32]; - sprintf(b, ", line %d:\n", lineNum); - m += b; - m += sourceLine; - m += '\n'; - String sourceLine2(sourceLine); - insertChars(sourceLine2, charNum, "[ERROR]"); - m += sourceLine2; - m += '\n'; - } else - m += ":\n"; - m += kindString(); - m += ": "; - m += message; - m += '\n'; - return m; -} - - -// -// Static Initializers -// - - -#ifndef _WIN32 -static void jsNewHandler() -{ - std::bad_alloc outOfMemory; - throw outOfMemory; -} - - -struct InitUtilities -{ - InitUtilities() {std::set_new_handler(&jsNewHandler);} -}; -#else -#include -static int jsNewHandler(size_t) -{ - std::bad_alloc outOfMemory; - throw outOfMemory; -} - - -struct InitUtilities -{ - InitUtilities() {_set_new_handler(&jsNewHandler);} -}; -#endif -InitUtilities initUtilities; diff --git a/mozilla/js2/src/utilities.h b/mozilla/js2/src/utilities.h index d5d89266ead..84f10fe183a 100644 --- a/mozilla/js2/src/utilities.h +++ b/mozilla/js2/src/utilities.h @@ -1,1515 +1,73 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#ifndef utilities_h -#define utilities_h +#ifndef utilities_h___ +#define utilities_h___ #include "systemtypes.h" -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug: standard identifiers should be in std namespace - using std::size_t; - using std::ptrdiff_t; - using std::va_list; - using std::strlen; - using std::strcpy; - using std::FILE; - using std::getc; - using std::fgets; - using std::fputc; - using std::fputs; - using std::sprintf; - using std::snprintf; - using std::vsnprintf; - using std::fprintf; - #define STD std - #define STATIC_CONST(type, expr) static const type expr -#else - #define STD - // Microsoft Visual C++ 6.0 bug: these identifiers should not begin with underscores - #define snprintf _snprintf - #define vsnprintf _vsnprintf - // Microsoft Visual C++ 6.0 bug: constants not supported - #define STATIC_CONST(type, expr) enum {expr} -#endif -using std::string; -using std::auto_ptr; - -#ifdef __GNUC__ // why doesn't g++ support iterator? -namespace std { - template - struct iterator { - typedef T value_type; - typedef Distance difference_type; - typedef Pointer pointer; - typedef Reference reference; - typedef Category iterator_category; - }; -}; -#endif - - -namespace JavaScript { - +namespace JavaScript +{ + // // Assertions // - #ifdef DEBUG - void Assert(const char *s, const char *file, int line); +#ifdef DEBUG + void Assert(const char *s, const char *file, int line); - #define ASSERT(_expr) ((_expr) ? (void)0 : JavaScript::Assert(#_expr, __FILE__, __LINE__)) - #define NOT_REACHED(_reasonStr) JavaScript::Assert(_reasonStr, __FILE__, __LINE__) - #define DEBUG_ONLY(_stmt) _stmt - #else - #define ASSERT(expr) - #define NOT_REACHED(reasonStr) - #define DEBUG_ONLY(_stmt) - #endif - - -// -// Numerics -// - - template N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;} - template N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;} - - -// -// Alignment -// - - template - struct AlignmentHelper { - char ch; - T t; - }; - #define ALIGNMENT_OF(T) offsetof(JavaScript::AlignmentHelper, t) - - -// -// Bit manipulation -// - - #define JS_BIT(n) ((uint32)1 << (n)) - #define JS_BITMASK(n) (JS_BIT(n) - 1) - - uint ceilingLog2(uint32 n); - uint floorLog2(uint32 n); - - -// -// Unicode UTF-16 characters and strings -// - - // Special char16s - namespace uni { - const char16 null = '\0'; - const char16 cr = '\r'; - const char16 lf = '\n'; - const char16 space = ' '; - const char16 ls = 0x2028; - const char16 ps = 0x2029; - } - const uint16 firstFormatChar = 0x200C; // Lowest Unicode Cf character - - inline char16 widen(char ch) {return static_cast(static_cast(ch));} - - // Use char16Value to compare char16's for inequality because an implementation may have char16's - // be either signed or unsigned. - inline uint16 char16Value(char16 ch) {return static_cast(ch);} - - // A string of UTF-16 characters. Nulls are allowed just like any other character. - // The string is not null-terminated. - // Use wstring if char16 is wchar_t. Otherwise use basic_string. - // - // Eventually we'll want to use a custom class better suited for JavaScript that generates less - // code bloat and separates the concepts of a fixed, read-only string from a mutable buffer that - // is expanding. For now, though, we use the standard basic_string. - typedef std::basic_string String; - typedef String string16; - typedef string16::const_iterator string16_citer; - typedef string string8; - typedef string8::const_iterator string8_citer; - - typedef uint32 char16orEOF; // A type that can hold any char16 plus one special value: ueof. - const char16orEOF char16eof = static_cast(-1); - - // If c is a char16, return it; if c is char16eof, return the character \uFFFF. - inline char16 char16orEOFToChar16(char16orEOF c) {return static_cast(c);} - -#ifndef _WIN32 - // Return a String containing the characters of the null-terminated C string cstr - // (without the trailing null). - inline String widenCString(const char *cstr) - { - size_t len = strlen(cstr); - const uchar *ucstr = reinterpret_cast(cstr); - return String(ucstr, ucstr+len); - } - - - // Widen and append length characters starting at chars to the end of str. - inline void appendChars(String &str, const char *chars, size_t length) - { - const uchar *uchars = reinterpret_cast(chars); - str.append(uchars, uchars + length); - } - - // Widen and append characters between begin and end to the end of str. - inline void appendChars(String &str, const char *begin, const char *end) - { - ASSERT(begin <= end); - str.append(reinterpret_cast(begin), reinterpret_cast(end)); - } - - // Widen and insert length characters starting at chars into the given position of str. - inline void insertChars(String &str, String::size_type pos, const char *chars, size_t length) - { - ASSERT(pos <= str.size()); - const uchar *uchars = reinterpret_cast(chars); - str.insert(str.begin() + pos, uchars, uchars + length); - } -#else // Microsoft VC6 bug: String constructor and append limited to char16 iterators - String widenCString(const char *cstr); - void appendChars(String &str, const char *chars, size_t length); - inline void appendChars(String &str, const char *begin, const char *end) - { - ASSERT(begin <= end); - appendChars(str, begin, static_cast(end - begin)); - } - void insertChars(String &str, String::size_type pos, const char *chars, size_t length); -#endif - void insertChars(String &str, String::size_type pos, const char *cstr); - - - String &operator+=(String &str, const char *cstr); - String operator+(const String &str, const char *cstr); - String operator+(const char *cstr, const String &str); - inline String &operator+=(String &str, char c) {return str += widen(c);} - inline void clear(String &s) {s.resize(0);} - - - class CharInfo { - uint32 info; // Word from table a. - - // Unicode character attribute lookup tables - static const uint8 x[]; - static const uint8 y[]; - static const uint32 a[]; - - public: - // Enumerated Unicode general category types - enum Type { - Unassigned = 0, // Cn - UppercaseLetter = 1, // Lu - LowercaseLetter = 2, // Ll - TitlecaseLetter = 3, // Lt - ModifierLetter = 4, // Lm - OtherLetter = 5, // Lo - NonSpacingMark = 6, // Mn - EnclosingMark = 7, // Me - CombiningSpacingMark = 8, // Mc - DecimalDigitNumber = 9, // Nd - LetterNumber = 10, // Nl - OtherNumber = 11, // No - SpaceSeparator = 12, // Zs - LineSeparator = 13, // Zl - ParagraphSeparator = 14, // Zp - Control = 15, // Cc - Format = 16, // Cf - PrivateUse = 18, // Co - Surrogate = 19, // Cs - DashPunctuation = 20, // Pd - StartPunctuation = 21, // Ps - EndPunctuation = 22, // Pe - ConnectorPunctuation = 23, // Pc - OtherPunctuation = 24, // Po - MathSymbol = 25, // Sm - CurrencySymbol = 26, // Sc - ModifierSymbol = 27, // Sk - OtherSymbol = 28 // So - }; - - enum Group { - NonIdGroup, // 0 May not be part of an identifier - FormatGroup, // 1 Format control - IdGroup, // 2 May start or continue a JS identifier (includes $ and _) - IdContinueGroup, // 3 May continue a JS identifier [(IdContinueGroup & -2) == IdGroup] - WhiteGroup, // 4 White space character (but not line break) - LineBreakGroup // 5 Line break character [(LineBreakGroup & -2) == WhiteGroup] - }; - - CharInfo() {} - CharInfo(char16 c): info(a[y[x[static_cast(c)>>6]<<6 | c&0x3F]]) {} - CharInfo(const CharInfo &ci): info(ci.info) {} - - friend Type cType(const CharInfo &ci) {return static_cast(ci.info & 0x1F);} - friend Group cGroup(const CharInfo &ci) {return static_cast(ci.info >> 16 & 7);} - - friend bool isAlpha(const CharInfo &ci) - { - return ((1<> cType(ci) & 1) != 0; - } - - friend bool isAlphanumeric(const CharInfo &ci) - { - return ((1<> cType(ci) & 1) != 0; - } - - // Return true if this character can start a JavaScript identifier - friend bool isIdLeading(const CharInfo &ci) {return cGroup(ci) == IdGroup;} - // Return true if this character can continue a JavaScript identifier - friend bool isIdContinuing(const CharInfo &ci) {return (cGroup(ci) & -2) == IdGroup;} - - // Return true if this character is a Unicode decimal digit (Nd) character - friend bool isDecimalDigit(const CharInfo &ci) {return cType(ci) == DecimalDigitNumber;} - // Return true if this character is a Unicode white space or line break character - friend bool isSpace(const CharInfo &ci) {return (cGroup(ci) & -2) == WhiteGroup;} - // Return true if this character is a Unicode line break character (LF, CR, LS, or PS) - friend bool isLineBreak(const CharInfo &ci) {return cGroup(ci) == LineBreakGroup;} - // Return true if this character is a Unicode format control character (Cf) - friend bool isFormat(const CharInfo &ci) {return cGroup(ci) == FormatGroup;} - - friend bool isUpper(const CharInfo &ci) {return cType(ci) == UppercaseLetter;} - friend bool isLower(const CharInfo &ci) {return cType(ci) == LowercaseLetter;} - - friend char16 toUpper(char16 c); - friend char16 toLower(char16 c); - }; - - inline bool isASCIIDecimalDigit(char16 c) {return c >= '0' && c <= '9';} - bool isASCIIHexDigit(char16 c, uint &digit); - - const char16 *skipWhiteSpace(const char16 *str, const char16 *strEnd); - - -// -// Algorithms -// - - // Assign zero to every element between first inclusive and last exclusive. - // This is equivalent ot fill(first, last, 0) but may be more efficient. - template - inline void zero(ForwardIterator first, ForwardIterator last) - { - while (first != last) { - *first = 0; - ++first; - } - } - - - // Assign zero to n elements starting at first. - // This is equivalent ot fill_n(first, n, 0) but may be more efficient. - template - inline void zero_n(ForwardIterator first, Size n) - { - while (n) { - *first = 0; - ++first; - --n; - } - } - - // Same as find(first, last, value) but may be more efficient because it doesn't - // use a reference for value. - template - inline InputIterator findValue(InputIterator first, InputIterator last, T value) - { - while (first != last && !(*first == value)) - ++first; - return first; - } - - -// -// Zones -// - - // A zone is a region of memory from which objects can be allocated individually. - // The memory in a zone is deallocated when the zone is deallocated or its clear - // method called. - - class Zone { - union Header { - Header *next; // Next block header in linked list - char padding[basicAlignment]; // Padding to ensure following block is fully aligned - }; // Block data follows header - - Header *headers; // Linked list of allocated blocks - char *freeBegin; // Pointer to free bytes left in current block - char *freeEnd; // Pointer to end of free bytes left in current block - size_t blockSize; // Size of individual arena blocks - - public: - explicit Zone(size_t blockSize = 1024); - private: - Zone(const Zone&); // No copy constructor - void operator=(const Zone&); // No assignment operator - public: - void clear(); - ~Zone() {clear();} - - private: - void *newBlock(size_t size); - public: - void *allocate(size_t size); - void *allocateUnaligned(size_t size); - }; - - -// -// Arenas -// - -#ifndef _WIN32 - // Pretend that obj points to a value of class T and call obj's destructor. - template - void classDestructor(void *obj) - { - static_cast(obj)->~T(); - } -#else // Microsoft Visual C++ 6.0 bug workaround - template - struct DestructorHolder { - static void destroy(void *obj) {static_cast(obj)->~T();} - }; -#endif - - // An arena is a region of memory from which objects either derived from ArenaObject or allocated - // using a ArenaAllocator can be allocated. Deleting these objects individually runs the destructors, - // if any, but does not deallocate the memory. On the other hand, the entire arena can be deallocated - // as a whole. - // - // One may also allocate other objects in an arena by using the Arena specialization of the global - // operator new. However, be careful not to delete any such objects explicitly! - // - // Destructors can be registered for objects (or parts of objects) allocated in the arena. These - // destructors are called, in reverse order of being registered, at the time the arena is deallocated - // or cleared. When registering destructors for an object O be careful not to delete O manually because that - // would run its destructor twice. - class Arena: public Zone { - struct DestructorEntry; - - DestructorEntry *destructorEntries; // Linked list of destructor registrations, ordered from most to least recently registered - - public: - explicit Arena(size_t blockSize = 1024): Zone(blockSize), destructorEntries(0) {} - private: - void runDestructors(); - public: - void clear() {runDestructors(); Zone::clear();} - ~Arena() {runDestructors();} - - private: - void newDestructorEntry(void (*destructor)(void *), void *object); - public: - // Ensure that object's destructor is called at the time the arena is deallocated or cleared. - // The destructors will be called in reverse order of being registered. - // registerDestructor might itself runs out of memory, in which case it immediately - // calls object's destructor before throwing bad_alloc. -#ifndef _WIN32 - template void registerDestructor(T *object) {newDestructorEntry(&classDestructor, object);} +# define ASSERT(_expr) \ + ((_expr) ? (void)0 : JavaScript::Assert(#_expr, __FILE__, __LINE__)) +# define NOT_REACHED(_reasonStr) \ + JavaScript::Assert(_reasonStr, __FILE__, __LINE__) +# define DEBUG_ONLY(_stmt) _stmt #else - template void registerDestructor(T *object) {newDestructorEntry(&DestructorHolder::destroy, object);} +# define ASSERT(expr) +# define NOT_REACHED(reasonStr) +# define DEBUG_ONLY(_stmt) #endif - }; - - - // Objects derived from this class will be contained in the Arena passed to the new operator. - struct ArenaObject { - void *operator new(size_t size, Arena &arena) {return arena.allocate(size);} - void *operator new[](size_t size, Arena &arena) {return arena.allocate(size);} - void operator delete(void *, Arena &) {} - void operator delete[](void *, Arena &) {} - private: - void operator delete(void *, size_t) {} - void operator delete[](void *) {} - }; - - - // Objects allocated by passing this class to standard containers will be contained in the Arena - // passed to the ArenaAllocator's constructor. - template - class ArenaAllocator { - Arena &arena; - - public: - typedef T value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T *pointer; - typedef const T *const_pointer; - typedef T &reference; - typedef const T &const_reference; - - static pointer address(reference r) {return &r;} - static const_pointer address(const_reference r) {return &r;} - - ArenaAllocator(Arena &arena): arena(arena) {} - template ArenaAllocator(const ArenaAllocator &u): arena(u.arena) {} - - pointer allocate(size_type n, const void *hint = 0) {return static_cast(arena.allocate(n*sizeof(T)));} - static void deallocate(pointer, size_type) {} - - static void construct(pointer p, const T &val) {new(p) T(val);} - static void destroy(pointer p) {p->~T();} - -#ifdef __GNUC__ // why doesn't g++ support numeric_limits? - static size_type max_size() {return size_type(-1) / sizeof(T);} -#else - static size_type max_size() {return std::numeric_limits::max() / sizeof(T);} -#endif - - template struct rebind {typedef ArenaAllocator other;}; - }; - - - String &newArenaString(Arena &arena); - String &newArenaString(Arena &arena, const String &str); - // -// Pools +// Random Crap // - - // A Pool holds a collection of objects of the same type. These objects can be - // allocated and deallocated inexpensively. - // To allocate a T, use new(pool) T(...), where pool has type Pool. - // To deallocate a T, use pool.destroy(t), where t has type T*. - template - class Pool: public Zone { - struct FreeList { - FreeList *next; // Next item in linked list of freed objects - }; - STATIC_CONST(size_t, entrySize = sizeof(T) >= sizeof(FreeList *) ? sizeof(T) : sizeof(FreeList *)); - - FreeList *freeList; // Head of linked list of freed objects - - public: - // clumpSize is the number of T's that are allocated at a time. - explicit Pool(size_t clumpSize): Zone(clumpSize * entrySize), freeList(0) {} - - // Allocate memory for a single T. Use this with a placement new operator to create a new T. - void *allocate() {if (freeList) {FreeList *p = freeList; freeList = p->next; return p;} return allocateUnaligned(entrySize);} - void deallocate(void *t) {FreeList *p = static_cast(t); p->next = freeList; freeList = p;} - - void destroy(T *t) {ASSERT(t); t->~T(); deallocate(t);} - }; - - -// -// Array auto_ptr's // + + template N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;} + template N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;} - // An ArrayAutoPtr holds a pointer to an array initialized by new T[x]. - // A regular auto_ptr cannot be used here because it deletes its pointer using - // delete rather than delete[]. - // An appropriate operator[] is also provided. - template - class ArrayAutoPtr { - T *ptr; - - public: - explicit ArrayAutoPtr(T *p = 0): ptr(p) {} - ArrayAutoPtr(ArrayAutoPtr &a): ptr(a.ptr) {a.ptr = 0;} - ArrayAutoPtr &operator=(ArrayAutoPtr &a) {reset(a.release());} - ~ArrayAutoPtr() {delete[] ptr;} - - T &operator*() const {return *ptr;} - T &operator->() const {return *ptr;} - template T &operator[](N i) const {return ptr[i];} - T *get() const {return ptr;} - T *release() {T *p = ptr; ptr = 0; return p;} - void reset(T *p = 0) {delete[] ptr; ptr = p;} - }; - - typedef ArrayAutoPtr CharAutoPtr; + uint ceilingLog2(uint32 n); + uint floorLog2(uint32 n); - -// -// Growable Arrays -// - - // A Buffer initially points to inline storage of initialSize elements of type T. - // The Buffer can be expanded via the expand method to increase its size by allocating - // storage from the heap. - template - class Buffer { - public: - T *buffer; // Pointer to the current buffer - size_t size; // Current size of the buffer - private: - T initialBuffer[initialSize]; // Initial buffer - public: - - Buffer(): buffer(initialBuffer), size(initialSize) {} - ~Buffer() {if (buffer != initialBuffer) delete[] buffer;} - - void expand(size_t newSize); - }; - - // Expand the buffer to size newSize, which must be greater than the current size. - // The buffer's contents are not preserved. - template - inline void Buffer::expand(size_t newSize) { - ASSERT(newSize > size); - if (buffer != initialBuffer) { - delete[] buffer; - buffer = 0; // For exception safety if the allocation below fails. - } - buffer = new T[newSize]; - size = newSize; - } - - - // See ArrayBuffer below. - template - class RawArrayBuffer { - T *const cache; // Pointer to a fixed-size cache for holding the buffer if it's small enough - protected: - T *buffer; // Pointer to the current buffer - size_t length; // Logical size of the buffer - size_t bufferSize; // Physical size of the buffer - #ifdef DEBUG - size_t maxReservedSize; // Maximum size reserved so far - #endif - - public: - RawArrayBuffer(T *cache, size_t cacheSize): cache(cache), buffer(cache), length(0), bufferSize(cacheSize) - {DEBUG_ONLY(maxReservedSize = 0);} - private: - RawArrayBuffer(const RawArrayBuffer&); // No copy constructor - void operator=(const RawArrayBuffer&); // No assignment operator - public: - ~RawArrayBuffer() {if (buffer != cache) delete[] buffer;} - - private: - void enlarge(size_t newLength); - public: - - // Methods that do not expand the buffer cannot throw exceptions. - size_t size() const {return length;} - operator bool() const {return length != 0;} - bool operator !() const {return length == 0;} - - T &front() {ASSERT(length); return *buffer;} - const T &front() const {ASSERT(length); return *buffer;} - T &back() {ASSERT(length); return buffer[length-1];} - const T &back() const {ASSERT(length); return buffer[length-1];} - T *contents() const {return buffer;} - - void reserve(size_t nElts); - T *reserve_back(size_t nElts = 1); - T *advance_back(size_t nElts = 1); - T *reserve_advance_back(size_t nElts = 1); - - void fast_push_back(const T &elt); - void push_back(const T &elt); - void append(const T *elts, size_t nElts); - void append(const T *begin, const T *end) {ASSERT(end >= begin); append(begin, static_cast(end - begin));} - - T &pop_back() {ASSERT(length); return buffer[--length];} - }; - - - // Enlarge the buffer so that it can hold at least newLength elements. - // May throw an exception, in which case the buffer is left unchanged. - template - void RawArrayBuffer::enlarge(size_t newLength) { - size_t newBufferSize = bufferSize * 2; - if (newBufferSize < newLength) - newBufferSize = newLength; - - auto_ptr newBuffer(new T[newBufferSize]); - T *oldBuffer = buffer; - std::copy(oldBuffer, oldBuffer + length, newBuffer.get()); - buffer = newBuffer.release(); - if (oldBuffer != cache) - delete[] oldBuffer; - bufferSize = newBufferSize; - } - - // Ensure that there is room to hold nElts elements in the buffer, without expanding the - // buffer's logical length. - // May throw an exception, in which case the buffer is left unchanged. - template - inline void RawArrayBuffer::reserve(size_t nElts) { - if (bufferSize < nElts) - enlarge(nElts); - #ifdef DEBUG - if (maxReservedSize < nElts) - maxReservedSize = nElts; - #endif - } - - // Ensure that there is room to hold nElts more elements in the buffer, without expanding the - // buffer's logical length. Return a pointer to the first element just past the logical length. - // May throw an exception, in which case the buffer is left unchanged. - template - inline T *RawArrayBuffer::reserve_back(size_t nElts) { - reserve(length + nElts); - return buffer[length]; - } - - // Advance the logical length by nElts, assuming that the memory has previously been reserved. - // Return a pointer to the first new element. - template - inline T *RawArrayBuffer::advance_back(size_t nElts) { - ASSERT(length + nElts <= maxReservedSize); - T *p = buffer + length; - length += nElts; - return p; - } - - // Combine the effects of reserve_back and advance_back. - template - inline T *RawArrayBuffer::reserve_advance_back(size_t nElts) { - reserve(length + nElts); - T *p = buffer + length; - length += nElts; - return p; - } - - // Same as push_back but assumes that the memory has previously been reserved. - // May throw an exception if copying elt throws one, in which case the buffer is left unchanged. - template - inline void RawArrayBuffer::fast_push_back(const T &elt) { - ASSERT(length < maxReservedSize); - buffer[length] = elt; - ++length; - } - - // Append elt to the back of the buffer. - // May throw an exception, in which case the buffer is left unchanged. - template - inline void RawArrayBuffer::push_back(const T &elt) { - *reserve_back() = elt; - ++length; - } - - // Append nElts elements elts to the back of the array buffer. - // May throw an exception, in which case the buffer is left unchanged. - template - void RawArrayBuffer::append(const T *elts, size_t nElts) - { - size_t newLength = length + nElts; - if (newLength > bufferSize) - enlarge(newLength); - std::copy(elts, elts + nElts, buffer + length); - length = newLength; - } - - - // An ArrayBuffer represents an array of elements of type T. The ArrayBuffer contains - // storage for a fixed size array of cacheSize elements; if this size is exceeded, the - // ArrayBuffer allocates the array from the heap. Elements can be appended to the back - // of the array using append. An ArrayBuffer can also act as a stack: elements can be - // pushed and popped from the back. - // - // All ArrayBuffer operations are atomic with respect to exceptions -- either they - // succeed or they do not affect the ArrayBuffer's existing elements and length. - // If T has a constructor, it must have a constructor with no arguments; that constructor - // is called at the time memory for the ArrayBuffer is allocated, just like when - // allocating a regular C++ array. - template - class ArrayBuffer: public RawArrayBuffer { - T cacheArray[cacheSize]; - public: - ArrayBuffer(): RawArrayBuffer(cacheArray, cacheSize) {} - }; - - -// -// Array Queues -// - - // See ArrayQueue below. - template - class RawArrayQueue { - T *const cache; // Pointer to a fixed-size cache for holding the buffer if it's small enough - protected: - T *buffer; // Pointer to the current buffer - T *bufferEnd; // Pointer to the end of the buffer - T *f; // Front end of the circular buffer, used for reading elements; buffer <= f < bufferEnd - T *b; // Back end of the circular buffer, used for writing elements; buffer < b <= bufferEnd - size_t length; // Number of elements used in the circular buffer - size_t bufferSize; // Physical size of the buffer - #ifdef DEBUG - size_t maxReservedSize; // Maximum size reserved so far - #endif - - public: - RawArrayQueue(T *cache, size_t cacheSize): - cache(cache), buffer(cache), bufferEnd(cache + cacheSize), f(cache), b(cache), length(0), bufferSize(cacheSize) - {DEBUG_ONLY(maxReservedSize = 0);} - private: - RawArrayQueue(const RawArrayQueue&); // No copy constructor - void operator=(const RawArrayQueue&); // No assignment operator - public: - ~RawArrayQueue() {if (buffer != cache) delete[] buffer;} - - private: - void enlarge(size_t newLength); - public: - - // Methods that do not expand the buffer cannot throw exceptions. - size_t size() const {return length;} - operator bool() const {return length != 0;} - bool operator !() const {return length == 0;} - - T &front() {ASSERT(length); return *f;} - const T &front() const {ASSERT(length); return *f;} - T &back() {ASSERT(length); return b[-1];} - const T &back() const {ASSERT(length); return b[-1];} - - T &pop_front() {ASSERT(length); --length; T &elt = *f++; if (f == bufferEnd) f = buffer; return elt;} - size_t pop_front(size_t nElts, T *&begin, T *&end); - T &pop_back() {ASSERT(length); --length; T &elt = *--b; if (b == buffer) b = bufferEnd; return elt;} - - void reserve_back(); - void reserve_back(size_t nElts); - T *advance_back(); - T *advance_back(size_t nElts, size_t &nEltsAdvanced); - - void fast_push_back(const T &elt); - void push_back(const T &elt); - - // Same as append but assumes that memory has previously been reserved. - // Does not throw exceptions. T::operator= must not throw exceptions. - template void fast_append(InputIter begin, InputIter end) { - size_t nElts = static_cast(std::distance(begin, end)); - ASSERT(length + nElts <= maxReservedSize); - while (nElts) { - size_t nEltsAdvanced; - T *dst = advance_back(nElts, nEltsAdvanced); - nElts -= nEltsAdvanced; - while (nEltsAdvanced--) { - *dst = *begin; ++dst; ++begin; - } - } - } - - // Append elements from begin to end to the back of the queue. T::operator= must not throw exceptions. - // reserve_back may throw an exception, in which case the queue is left unchanged. - template void append(InputIter begin, InputIter end) { - size_t nElts = static_cast(std::distance(begin, end)); - reserve_back(nElts); - while (nElts) { - size_t nEltsAdvanced; - T *dst = advance_back(nElts, nEltsAdvanced); - nElts -= nEltsAdvanced; - while (nEltsAdvanced--) { - *dst = *begin; ++dst; ++begin; - } - } - } - }; - - // Pop between one and nElts elements from the front of the queue. Set begin and end - // to an array of the first n elements, where n is the return value. The popped elements - // may be accessed until the next non-const operation. - // Does not throw exceptions. - template - size_t RawArrayQueue::pop_front(size_t nElts, T *&begin, T *&end) { - ASSERT(nElts <= length); - begin = f; - size_t eltsToEnd = static_cast(bufferEnd - f); - if (nElts < eltsToEnd) { - length -= nElts; - f += nElts; - end = f; - return nElts; - } else { - length -= eltsToEnd; - end = bufferEnd; - f = buffer; - return eltsToEnd; - } - } - - // Enlarge the buffer so that it can hold at least newLength elements. - // May throw an exception, in which case the queue is left unchanged. - template - void RawArrayQueue::enlarge(size_t newLength) { - size_t newBufferSize = bufferSize * 2; - if (newBufferSize < newLength) - newBufferSize = newLength; - - auto_ptr newBuffer(new T[newBufferSize]); - T *oldBuffer = buffer; - size_t eltsToEnd = static_cast(bufferEnd - f); - if (eltsToEnd <= length) - std::copy(f, f + eltsToEnd, newBuffer.get()); - else { - std::copy(f, bufferEnd, newBuffer.get()); - std::copy(oldBuffer, b, newBuffer.get() + eltsToEnd); - } - buffer = newBuffer.release(); - f = buffer; - b = buffer + length; - if (oldBuffer != cache) - delete[] oldBuffer; - bufferSize = newBufferSize; - } - - // Ensure that there is room to hold one more element at the back of the queue, without expanding the - // queue's logical length. - // May throw an exception, in which case the queue is left unchanged. - template - inline void RawArrayQueue::reserve_back() { - if (length == bufferSize) - enlarge(length + 1); - #ifdef DEBUG - if (maxReservedSize <= length) - maxReservedSize = length + 1; - #endif - } - - // Ensure that there is room to hold nElts more elements at the back of the queue, without expanding the - // queue's logical length. - // May throw an exception, in which case the queue is left unchanged. - template - inline void RawArrayQueue::reserve_back(size_t nElts) { - nElts += length; - if (bufferSize < nElts) - enlarge(nElts); - #ifdef DEBUG - if (maxReservedSize < nElts) - maxReservedSize = nElts; - #endif - } - - // Advance the back of the queue by one element, assuming that the memory has previously been reserved. - // Return a pointer to that new element. - // Does not throw exceptions. - template - inline T *RawArrayQueue::advance_back() { - ASSERT(length < maxReservedSize); - ++length; - if (b == bufferEnd) - b = buffer; - return b++; - } - - // Advance the back of the queue by between one and nElts elements and return a pointer to them, - // assuming that the memory has previously been reserved. - // nEltsAdvanced gets the actual number of elements advanced. - // Does not throw exceptions. - template - T *RawArrayQueue::advance_back(size_t nElts, size_t &nEltsAdvanced) { - size_t newLength = length + nElts; - ASSERT(newLength <= maxReservedSize); - if (nElts) { - T *b2 = b; - if (b2 == bufferEnd) - b2 = buffer; - - size_t room = static_cast(bufferEnd - b2); - if (nElts > room) { - nElts = room; - newLength = length + nElts; - } - length = newLength; - nEltsAdvanced = nElts; - b = b2 + nElts; - return b2; - } else { - nEltsAdvanced = 0; - return 0; - } - } - - // Same as push_back but assumes that the memory has previously been reserved. - // May throw an exception if copying elt throws one, in which case the queue is left unchanged. - template - inline void RawArrayQueue::fast_push_back(const T &elt) { - ASSERT(length < maxReservedSize); - T *b2 = b; - if (b2 == bufferEnd) - b2 = buffer; - *b2 = elt; - b = b2 + 1; - ++length; - } - - // Append elt to the back of the queue. - // May throw an exception, in which case the queue is left unchanged. - template - inline void RawArrayQueue::push_back(const T &elt) { - reserve_back(); - T *b2 = b == bufferEnd ? buffer : b; - *b2 = elt; - b = b2 + 1; - ++length; - } - - - // An ArrayQueue represents an array of elements of type T that can be written at its - // back end and read at its front or back end. In addition, arrays of multiple elements may be - // written at the back end or read at the front end. The ArrayQueue contains storage for a fixed size - // array of cacheSize elements; if this size is exceeded, the ArrayQueue allocates the - // array from the heap. - template - class ArrayQueue: public RawArrayQueue { - T cacheArray[cacheSize]; - public: - ArrayQueue(): RawArrayQueue(cacheArray, cacheSize) {} - }; - - -// -// Linked Lists -// - - // In some cases it is desirable to manipulate ordinary C-style linked lists as though - // they were STL-like sequences. These classes define STL forward iterators that walk - // through singly-linked lists of objects threaded through fields named 'next'. The type - // parameter E must be a class that has a member named 'next' whose type is E* or const E*. - - template - class ListIterator: public std::iterator { - E *element; - - public: - ListIterator() {} - explicit ListIterator(E *e): element(e) {} - - E &operator*() const {return *element;} - E *operator->() const {return element;} - ListIterator &operator++() {element = element->next; return *this;} - ListIterator operator++(int) {ListIterator i(*this); element = element->next; return i;} - friend bool operator==(const ListIterator &i, const ListIterator &j) {return i.element == j.element;} - friend bool operator!=(const ListIterator &i, const ListIterator &j) {return i.element != j.element;} - }; - - - template - #ifndef _WIN32 // Microsoft VC6 bug: std::iterator should support five template arguments - class ConstListIterator: public std::iterator { - #else - class ConstListIterator: public std::iterator { - #endif - const E *element; - - public: - ConstListIterator() {} - ConstListIterator(const ListIterator &i): element(&*i) {} - explicit ConstListIterator(const E *e): element(e) {} - - const E &operator*() const {return *element;} - const E *operator->() const {return element;} - ConstListIterator &operator++() {element = element->next; return *this;} - ConstListIterator operator++(int) {ConstListIterator i(*this); element = element->next; return i;} - friend bool operator==(const ConstListIterator &i, const ConstListIterator &j) {return i.element == j.element;} - friend bool operator!=(const ConstListIterator &i, const ConstListIterator &j) {return i.element != j.element;} - }; - - -// -// Doubly Linked Lists -// - - // A ListQueue provides insert and delete operations on a doubly-linked list of objects - // threaded through fields named 'next' and 'prev'. The type parameter E must be a class - // derived from ListQueueEntry. - // The ListQueue does not own its elements. They must be deleted explicitly if needed. - - struct ListQueueEntry { - ListQueueEntry *next; // Next entry in linked list - ListQueueEntry *prev; // Previous entry in linked list - - #ifdef DEBUG - ListQueueEntry(): next(0), prev(0) {} - #endif - }; - - template - struct ListQueue: private ListQueueEntry { - ListQueue() {next = this; prev = this;} - - operator bool() const {return next != static_cast(this);} // Return true if the ListQueue is nonempty - bool operator !() const {return next == static_cast(this);} // Return true if the ListQueue is empty - - E &front() const {ASSERT(operator bool()); return *static_cast(next);} - E &back() const {ASSERT(operator bool()); return *static_cast(prev);} - - void push_front(E &elt) {ASSERT(!elt.next && !elt.prev); elt.next = next; elt.prev = this; next->prev = &elt; next = &elt;} - void push_back(E &elt) {ASSERT(!elt.next && !elt.prev); elt.next = this; elt.prev = prev; prev->next = &elt; prev = &elt;} - E &pop_front() {ASSERT(operator bool()); E *elt = static_cast(next); next = elt->next; next->prev = this; - DEBUG_ONLY(elt->next = 0; elt->prev = 0;) return *elt;} - E &pop_back() {ASSERT(operator bool()); E *elt = static_cast(prev); prev = elt->prev; prev->next = this; - DEBUG_ONLY(elt->next = 0; elt->prev = 0;) return *elt;} - }; - - -// -// Bit Sets -// - - template - class BitSet { - STATIC_CONST(size_t, nWords = (size+31)>>5); - STATIC_CONST(uint32, lastWordMask = (2u<<((size-1)&31)) - 1); - uint32 words[nWords]; // Bitmap of bits. The first word contains bits 0(LSB)...31(MSB), the second contains bits 32...63, etc. - - public: - void clear() {zero(words, words+nWords);} - BitSet() {clear();} - // Construct a BitSet out of an array of alternating low (inclusive) and high (exclusive) ends of ranges of set bits. - // The array is terminated by a 0,0 range. - template explicit BitSet(In a) {clear(); size_t low, high; while (low = *a++, (high = *a++) != 0) setRange(low, high);} - - bool operator[](size_t i) const {ASSERT(i < size); return static_cast(words[i>>5]>>(i&31) & 1);} - bool none() const; - bool operator==(const BitSet &s) const; - bool operator!=(const BitSet &s) const; - - void set(size_t i) {ASSERT(i < size); words[i>>5] |= 1u<<(i&31);} - void reset(size_t i) {ASSERT(i < size); words[i>>5] &= ~(1u<<(i&31));} - void flip(size_t i) {ASSERT(i < size); words[i>>5] ^= 1u<<(i&31);} - void setRange(size_t low, size_t high); - void resetRange(size_t low, size_t high); - void flipRange(size_t low, size_t high); - }; - - // Return true if all bits are clear. - template - inline bool BitSet::none() const { - if (nWords == 1) - return !words[0]; - else { - const uint32 *w = words; - while (w != words + nWords) - if (*w++) - return false; - return true; - } - } - - // Return true if the BitSets are equal. - template - inline bool BitSet::operator==(const BitSet &s) const { - if (nWords == 1) - return words[0] == s.words[0]; - else - return std::equal(words, s.words); - } - - // Return true if the BitSets are not equal. - template - inline bool BitSet::operator!=(const BitSet &s) const { - return !operator==(s); - } - - // Set all bits between low inclusive and high exclusive. - template - void BitSet::setRange(size_t low, size_t high) { - ASSERT(low <= high && high <= size); - if (low != high) - if (nWords == 1) - words[0] |= (2u<<(high-1)) - (1u<>5); - uint32 *wHigh = words + (high>>5); - uint32 l = 1u << (low&31); - uint32 h = 2u << (high&31); - if (w == wHigh) - *w |= h - l; - else { - *w++ |= -l; - while (w != wHigh) - *w++ = static_cast(-1); - *w |= h - 1; - } - } - } - - // Clear all bits between low inclusive and high exclusive. - template - void BitSet::resetRange(size_t low, size_t high) { - ASSERT(low <= high && high <= size); - if (low != high) - if (nWords == 1) - words[0] &= (1u<>5); - uint32 *wHigh = words + (high>>5); - uint32 l = 1u << (low&31); - uint32 h = 2u << (high&31); - if (w == wHigh) - *w &= l - 1 - h; - else { - *w++ &= l - 1; - while (w != wHigh) - *w++ = 0; - *w &= -h; - } - } - } - - // Invert all bits between low inclusive and high exclusive. - template - void BitSet::flipRange(size_t low, size_t high) { - ASSERT(low <= high && high <= size); - if (low != high) - if (nWords == 1) - words[0] ^= (2u<<(high-1)) - (1u<>5); - uint32 *wHigh = words + (high>>5); - uint32 l = 1u << (low&31); - uint32 h = 2u << (high&31); - if (w == wHigh) - *w ^= h - l; - else { - *w++ ^= -l; - while (w != wHigh) - *w++ ^= static_cast(-1); - *w ^= h - 1; - } - } - } - - -// -// Input -// - - class LineReader { - FILE *in; // File from which currently reading - bool crWasLast; // True if a CR character was the last one read - - public: - explicit LineReader(FILE *in): in(in), crWasLast(false) {} - - size_t readLine(string &str); - size_t readLine(String &wstr); - }; - - -// -// Output -// - - // Print the characters between begin and end to the given file. These characters - // may include nulls. - size_t printChars(FILE *file, const char *begin, const char *end); - - #ifndef XP_MAC_MPW - inline size_t printChars(FILE *file, const char *begin, const char *end) - {ASSERT(end >= begin); return STD::fwrite(begin, 1, static_cast(end - begin), file);} - #endif - - - // A Formatter is an abstract base class representing a simplified output stream. - // One can print text to a Formatter by using << and the various global print... methods below. - // Formatters accept both char and char16 text and convert as appropriate to their actual stream. - class Formatter { - protected: - virtual void printChar8(char ch); - virtual void printChar16(char16 ch); - virtual void printZStr8(const char *str); - virtual void printStr8(const char *strBegin, const char *strEnd) = 0; - virtual void printStr16(const char16 *strBegin, const char16 *strEnd) = 0; - virtual void printString16(const String &s); - virtual void printVFormat8(const char *format, va_list args); - public: - - Formatter &operator<<(char ch) {printChar8(ch); return *this;} - Formatter &operator<<(char16 ch) {printChar16(ch); return *this;} - Formatter &operator<<(const char *str) {printZStr8(str); return *this;} - Formatter &operator<<(const String &s) {printString16(s); return *this;} - Formatter &operator<<(uint32 i) {printFormat(*this, "%u", i); return *this;} - - friend void printString(Formatter &f, const char *strBegin, const char *strEnd) {f.printStr8(strBegin, strEnd);} - friend void printString(Formatter &f, const char16 *strBegin, const char16 *strEnd) {f.printStr16(strBegin, strEnd);} - friend void printFormat(Formatter &f, const char *format, ...) {va_list args; va_start(args, format); f.printVFormat8(format, args); va_end(args);} - }; - - void printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format); - - void printChar(Formatter &f, char ch, int count); - void printChar(Formatter &f, char16 ch, int count); - inline void printDec(Formatter &f, int32 i, int nDigits = 0, char pad = ' ') {printNum(f, (uint32)i, nDigits, pad, "%i");} - inline void printDec(Formatter &f, uint32 i, int nDigits = 0, char pad = ' ') {printNum(f, i, nDigits, pad, "%u");} - inline void printHex(Formatter &f, int32 i, int nDigits = 0, char pad = '0') {printNum(f, (uint32)i, nDigits, pad, "%X");} - inline void printHex(Formatter &f, uint32 i, int nDigits = 0, char pad = '0') {printNum(f, i, nDigits, pad, "%X");} - void printPtr(Formatter &f, void *p); - - - // An AsciiFileFormatter is a Formatter that prints to a standard ASCII file or stream. - // Characters with Unicode values of 256 or higher are converted to escape sequences. - // Selected lower characters can also be converted to escape sequences; these are specified by - // set bits in the BitSet passed to the constructor. - class AsciiFileFormatter: public Formatter { - FILE *file; - BitSet<256> filter; // Set of first 256 characters that are to be converted to escape sequences - bool filterEmpty; // True if filter passes all 256 characters - public: - static BitSet<256> defaultFilter;// Default value of filter when not given in the constructor - - explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0); - - private: - bool filterChar(char ch) {return filter[static_cast(ch)];} - bool filterChar(char16 ch) {return char16Value(ch) >= 0x100 || filter[char16Value(ch)];} - protected: - void printChar8(char ch); - void printChar16(char16 ch); - void printZStr8(const char *str); - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - }; - - extern AsciiFileFormatter stdOut; - extern AsciiFileFormatter stdErr; - - - // A StringFormatter is a Formatter that prints to a String. - class StringFormatter: public Formatter { - String s; - - public: - const String& getString() { return s; } - void clear() {JavaScript::clear(s);} - protected: - void printChar8(char ch); - void printChar16(char16 ch); - void printZStr8(const char *str); - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - void printString16(const String &str); - }; - - -// -// Formatted Output -// - - class PrettyPrinter: public Formatter { - public: - STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF); - class Region; - class Indent; - class Block; - - private: - STATIC_CONST(uint32, infiniteLength = 0x80000000); - const uint32 lineWidth; // Current maximum desired line width - - struct BlockInfo { - uint32 margin; // Saved margin before this block's beginning - uint32 lastBreak; // Saved lastBreak before this block's beginning - bool fits; // True if this entire block fits on one line - }; - // Variables for the back end that prints to the destination - Formatter &outputFormatter; // Destination formatter on which the result should be printed - uint32 outputPos; // Number of characters printed on current output line - uint32 lineNum; // Serial number of current line - uint32 lastBreak; // Number of line just after the last break that occurred in this block - uint32 margin; // Current left margin in spaces - ArrayBuffer savedBlocks; // Stack of saved information about partially printed blocks - - // Variables for the front end that calculates block sizes - struct Item: ListQueueEntry { - enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, linearBreak, fillBreak}; - - const Kind kind; // The kind of this text sequence - bool lengthKnown; // True if totalLength is known; always true for text, blockEnd, and indent Items - uint32 length; // Length of this text sequence, number of spaces for this break, or delta for indent or indentBlockBegin - uint32 totalLength; // Total length of this block (for blockBegin) or length of this break plus following clump (for breaks) - // If lengthKnown is false, this is the serialPos of this Item instead of a length - bool hasKind(Kind k) const {return kind == k;} - - explicit Item(Kind kind): kind(kind), lengthKnown(true) {} - Item(Kind kind, uint32 length): kind(kind), lengthKnown(true), length(length) {} - Item(Kind kind, uint32 length, uint32 beginSerialPos): - kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {} - - void computeTotalLength(uint32 endSerialPos) {ASSERT(!lengthKnown); lengthKnown = true; totalLength = endSerialPos - totalLength;} - }; - - #ifdef DEBUG - Region *topRegion; // Most deeply nested Region - #endif - uint32 nNestedBlocks; // Number of nested Blocks - uint32 leftSerialPos; // The difference rightSerialPos-leftSerialPos is always the number of characters that - uint32 rightSerialPos; // would be output by printing activeItems if they all fit on one line; - // only the difference matters -- the absolute values are irrelevant and may wrap around 2^32. - ArrayQueue itemStack; // Stack of enclosing nested Items whose lengths have not yet been determined - // itemStack always has room for at least nNestedBlocks extra entries so that end Items may be added - // without throwing an exception. - Pool itemPool; // Pool from which to allocate activeItems - ListQueue activeItems; // Queue of items left to be printed - ArrayQueue itemText; // Text of text items in activeItems, in the same order as in activeItems - - public: - static uint32 defaultLineWidth; // Default for lineWidth if not given to the constructor - - explicit PrettyPrinter(Formatter &f, uint32 lineWidth = defaultLineWidth); - private: - PrettyPrinter(const PrettyPrinter&); // No copy constructor - void operator=(const PrettyPrinter&); // No assignment operator - public: - ~PrettyPrinter(); - - private: - void outputBreak(bool sameLine, uint32 nSpaces); - bool reduceLeftActiveItems(uint32 rightOffset); - void reduceRightActiveItems(); - - Item &beginIndent(int32 offset); - void endIndent(Item &i); - - Item &beginBlock(Item::Kind kind, int32 offset); - void endBlock(Item &i); - - void conditionalBreak(uint32 nSpaces, Item::Kind kind); - - protected: - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - public: - - void requiredBreak(); - void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::linearBreak);} - void linearBreak(uint32 nSpaces, bool required); - void fillBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::fillBreak);} - - void end(); - - friend class Region; - friend class Indent; - friend class Block; - - class Region { - #ifdef DEBUG - Region *next; // Link to next most deeply nested Region - #endif - protected: - PrettyPrinter &pp; - - Region(PrettyPrinter &pp): pp(pp) {DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;)} - private: - Region(const Region&); // No copy constructor - void operator=(const Region&); // No assignment operator - protected: - #ifdef DEBUG - ~Region() {pp.topRegion = next;} - #endif - }; - - // Use an Indent object to temporarily indent a PrettyPrinter by the offset given to the Indent's constructor. - // The PrettyPrinter's margin is set back to its original value when the Indent object is destroyed. - // Using an Indent object is exception-safe; no matter how control leaves an Indent scope, the indent is undone. - // Scopes of Indent and Block objects must be properly nested. - class Indent: public Region { - Item &endItem; // The Item returned by beginIndent - public: - Indent(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginIndent(offset)) {} - ~Indent() {pp.endIndent(endItem);} - }; - - // Use a Block object to temporarily enter a PrettyPrinter block. If an offset is provided, line breaks inside - // the block are indented by that offset relative to the existing indent; otherwise, line breaks inside the block - // are indented to the current output position. The block lasts until the Block object is destroyed. - // Scopes of Indent and Block objects must be properly nested. - class Block: public Region { - Item &endItem; // The Item returned by beginBlock - public: - explicit Block(PrettyPrinter &pp): Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {} - Block(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, offset)) {} - ~Block() {pp.endBlock(endItem);} - }; - }; - - -// -// Exceptions -// - - // A JavaScript exception (other than out-of-memory, for which we use the standard C++ - // exception bad_alloc). - struct Exception { - enum Kind { - syntaxError, - stackOverflow - }; - - Kind kind; // The exception's kind - String message; // The detailed message - String sourceFile; // A description of the source code that caused the error - uint32 lineNum; // Number of line that caused the error - uint32 charNum; // Character offset within the line that caused the error - uint32 pos; // Offset within the input of the error - String sourceLine; // The text of the source line - - Exception(Kind kind, const String &message): kind(kind), message(message), lineNum(0), charNum(0) {} - Exception(Kind kind, const String &message, const String &sourceFile, uint32 lineNum, uint32 charNum, uint32 pos, - const String &sourceLine): - kind(kind), message(message), sourceFile(sourceFile), lineNum(lineNum), charNum(charNum), pos(pos), sourceLine(sourceLine) {} - Exception(Kind kind, const String &message, const String &sourceFile, uint32 lineNum, uint32 charNum, uint32 pos, - const char16 *sourceLineBegin, const char16 *sourceLineEnd): - kind(kind), message(message), sourceFile(sourceFile), lineNum(lineNum), charNum(charNum), pos(pos), - sourceLine(sourceLineBegin, sourceLineEnd) {} - - bool hasKind(Kind k) const {return kind == k;} - const char *kindString() const; - String fullMessage() const; - }; - - - // Throw a stackOverflow exception if the execution stack has gotten too large. - inline void checkStackSize() {} } - -inline void *operator new(size_t size, JavaScript::Arena &arena) {return arena.allocate(size);} -#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished - inline void *operator new[](size_t size, JavaScript::Arena &arena) {return arena.allocate(size);} -#endif - -// Global delete operators. These are only called in the rare cases that a constructor throws an exception -// and has to undo an operator new. An explicit delete statement will never invoke these. -inline void operator delete(void *, JavaScript::Arena &) {} -#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished - inline void operator delete[](void *, JavaScript::Arena &) {} -#endif - -template -inline void *operator new(size_t DEBUG_ONLY(size), JavaScript::Pool &pool) {ASSERT(size == sizeof(T)); return pool.allocate();} -template -inline void operator delete(void *t, JavaScript::Pool &pool) {pool.deallocate(t);} -#endif +#endif /* utilities_h___ */ diff --git a/mozilla/js2/src/world.cpp b/mozilla/js2/src/world.cpp index e59ab744ae8..a5519a88294 100644 --- a/mozilla/js2/src/world.cpp +++ b/mozilla/js2/src/world.cpp @@ -1,39 +1,54 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ #include "world.h" -namespace JS = JavaScript; - +namespace JavaScript +{ // Return an existing StringAtom corresponding to the String s if there is // one; if not, create a new StringAtom with String s and return that StringAtom. -JS::StringAtom &JS::StringAtomTable::operator[](const String &s) -{ - HT::Reference r(ht, s); - if (r) - return *r; - else - return ht.insert(r, s); -} + StringAtom & + StringAtomTable::operator[](const String &s) + { + HT::Reference r(ht, s); + if (r) + return *r; + else + return ht.insert(r, s); + } - -JS::World::World() -{ - Token::initKeywords(*this); + World::World() + { + Token::initKeywords(*this); + } } diff --git a/mozilla/js2/src/world.h b/mozilla/js2/src/world.h index 7c65ff55207..b0dc60da600 100644 --- a/mozilla/js2/src/world.h +++ b/mozilla/js2/src/world.h @@ -1,73 +1,90 @@ -// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// The contents of this file are subject to the Netscape Public -// License Version 1.1 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of -// the License at http://www.mozilla.org/NPL/ -// -// Software distributed under the License is distributed on an "AS -// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr -// implied. See the License for the specific language governing -// rights and limitations under the License. -// -// The Original Code is the JavaScript 2 Prototype. -// -// The Initial Developer of the Original Code is Netscape -// Communications Corporation. Portions created by Netscape are -// Copyright (C) 1998 Netscape Communications Corporation. All -// Rights Reserved. +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -#ifndef world_h -#define world_h +#ifndef world_h___ +#define world_h___ -#include "utilities.h" +#include "strings.h" +#include "token.h" #include "hash.h" -#include "parser.h" namespace JavaScript { - + // // String atom management // // A StringAtom is a String for which the following guarantee applies: -// StringAtoms A and B have the same character sequences if and only if A and B are the -// same StringAtom. +// StringAtoms A and B have the same character sequences if and only if A and +// B are the same StringAtom. - class StringAtom: public String { - public: - Token::Kind tokenKind; // Token::Kind if this is a keyword; Token::identifier if not + class StringAtom : public String { + public: + // Token::Kind if this is a keyword; Token::identifier if not + Token::Kind tokenKind; + + explicit StringAtom(const String &s) : + String(s), tokenKind(Token::identifier) {} + private: + StringAtom(const StringAtom&); // No copy constructor + void operator=(const StringAtom&); // No assignment operator + }; + + inline bool operator==(const StringAtom &s1, const StringAtom &s2) { + return &s1 == &s2; + } + inline bool operator!=(const StringAtom &s1, const StringAtom &s2) { + return &s1 != &s2; + } - explicit StringAtom(const String &s): String(s), tokenKind(Token::identifier) {} - private: - StringAtom(const StringAtom&); // No copy constructor - void operator=(const StringAtom&); // No assignment operator - }; - - inline bool operator==(const StringAtom &s1, const StringAtom &s2) {return &s1 == &s2;} - inline bool operator!=(const StringAtom &s1, const StringAtom &s2) {return &s1 != &s2;} - - - class StringAtomTable { - typedef HashTable HT; - HT ht; - - public: - StringAtom &operator[](const String &s); - - StringAtom &operator[](const char *s) - { + class StringAtomTable { + typedef HashTable HT; + HT ht; + + public: + StringAtom &operator[](const String &s); + + StringAtom &operator[](const char *s) { return operator[](widenCString(s)); } - }; - - - class World { - public: - StringAtomTable identifiers; - - World(); - }; + }; + + class World { + public: + StringAtomTable identifiers; + + World(); + }; } #endif diff --git a/mozilla/js2/tests/cpp/Makefile.am b/mozilla/js2/tests/cpp/Makefile.am new file mode 100644 index 00000000000..06b223848e9 --- /dev/null +++ b/mozilla/js2/tests/cpp/Makefile.am @@ -0,0 +1,10 @@ + +include $(top_srcdir)/common.mk + +INCLUDES = -I$(top_srcdir)/src/ +LIBS = -L$(top_srcdir)/src/ -ljs2 + +bin_PROGRAMS = parser_test + +parser_test_DEPENDENCIES = $(top_srcdir)/src/libjs2.a +parser_test_SOURCES = parser_test.cpp \ No newline at end of file diff --git a/mozilla/js2/tests/cpp/basics.cpp b/mozilla/js2/tests/cpp/basics.cpp new file mode 100644 index 00000000000..41e0542b078 --- /dev/null +++ b/mozilla/js2/tests/cpp/basics.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include + +using namespace std; + +struct Arena { + const char *name; + + Arena(const char *name): name(name) {} +}; + + +void *operator new(size_t size, Arena &arena); +void operator delete(void *p); + +void *operator new(size_t size, Arena &arena) +{ + void *p = malloc(size); + printf("Allocating %d bytes at %p using arena \"%s\"\n", size, p, arena.name); + return p; +} + +#ifndef __MWERKS__ +void operator delete(void *p, Arena &arena) +{ + printf("Deleting object at %p using arena \"%s\"\n", p, arena.name); +} +#endif + + +void operator delete(void *p) +{ + printf("Deleting object at %p\n", p); +} + + +struct C { + int n; + + C(int n, bool bad = false); + ~C(); +}; + +struct Exception { + int num; + + explicit Exception(int n): num(n) {} +}; + + +C::C(int n, bool bad): n(n) +{ + printf("Constructing C #%d at %p\n", n, this); + if (bad) { + printf("Throwing %d; constructor aborted\n", n); + throw Exception(n); + } +} + +C::~C() +{ + printf("Destroying C #%d at %p\n", n, this); +} + + +static void constructorTest1(int n, bool bad) +{ + try { + printf("Calling C(%d,%d)\n", n, (int)bad); + { + C c(n, bad); + printf("We have C #%d\n", c.n); + } + printf("C is out of scope\n"); + } catch (Exception &e) { + printf("Caught exception %d\n", e.num); + } + printf("\n"); +} + + +static void constructorTest2(int n, bool bad) +{ + try { + printf("Calling new C(%d,%d)\n", n, (int)bad); + { + C *c = new C(n, bad); + printf("We have C #%d\n", c->n); + delete c; + } + printf("C is out of scope\n"); + } catch (Exception &e) { + printf("Caught exception %d\n", e.num); + } + printf("\n"); +} + + +static void constructorTest3(int n, bool bad) +{ + try { + printf("Calling new(arena) C(%d,%d)\n", n, (int)bad); + { + Arena arena("My arena"); + C *c = new(arena) C(n, bad); + printf("We have C #%d\n", c->n); + } + printf("C is out of scope\n"); + } catch (Exception &e) { + printf("Caught exception %d\n", e.num); + } + printf("\n"); +} + + +int main() +{ + printf("Beginning constructor tests\n\n"); + constructorTest1(1, false); + constructorTest1(2, true); + constructorTest2(3, false); + constructorTest2(4, true); + constructorTest3(5, false); + constructorTest3(6, true); + printf("Ending constructor tests\n"); + return 0; +} diff --git a/mozilla/js2/tests/cpp/parser_test.cpp b/mozilla/js2/tests/cpp/parser_test.cpp new file mode 100644 index 00000000000..b5e245eb5a2 --- /dev/null +++ b/mozilla/js2/tests/cpp/parser_test.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#include +#include "world.h" +#include "parser.h" +#include "reader.h" + +using namespace JavaScript; + +World world; +const bool showTokens = false; +const String consoleName = widenCString(""); + +#if defined(XP_MAC) && !defined(XP_MAC_MPW) +#include +#include + +static char *mac_argv[] = {"js2", 0}; + +static void initConsole(StringPtr consoleName, const char* startupMessage, + int &argc, char **&argv) +{ + SIOUXSettings.autocloseonquit = false; + SIOUXSettings.asktosaveonclose = false; + SIOUXSetTitle(consoleName); + + // Set up a buffer for stderr (otherwise it's a pig). + static char buffer[BUFSIZ]; + setvbuf(stderr, buffer, _IOLBF, BUFSIZ); + + JavaScript::stdOut << startupMessage; + + argc = 1; + argv = mac_argv; +} +#endif + +// Interactively read a line from the input stream in and put it into +// s. Return false if reached the end of input before reading anything. +static bool promptLine(LineReader &inReader, string &s, const char *prompt) +{ +#if !defined XP_MAC_MPW + if (prompt) + stdOut << prompt; +#endif + return inReader.readLine(s) != 0; +} + +static void readEvalPrint(FILE *in, World &world) +{ + String buffer; + string line; + LineReader inReader(in); + + while (promptLine(inReader, line, buffer.empty() ? "js parser> " : "> ")) { + appendChars(buffer, line.data(), line.size()); + try { + Arena a; + Parser p(world, a, buffer, consoleName); + + if (showTokens) { + Lexer &l = p.lexer; + while (true) { + const Token &t = l.get(true); + if (t.hasKind(Token::end)) + break; + stdOut << ' '; + t.print(stdOut, true); + } + stdOut << '\n'; + } else { + StmtNode *parsedStatements = p.parseProgram(); + ASSERT(p.lexer.peek(true).hasKind(Token::end)); + { + PrettyPrinter f(stdOut, 30); + { + PrettyPrinter::Block b(f, 2); + f << "Program ="; + f.linearBreak(1); + StmtNode::printStatements(f, parsedStatements); + } + f.end(); + } + stdOut << '\n'; + } + clear(buffer); + } catch (Exception &e) { + /* If we got a syntax error on the end of input, + * then wait for a continuation + * of input rather than printing the error message. */ + if (!(e.hasKind(Exception::syntaxError) && + e.lineNum && e.pos == buffer.size() && + e.sourceFile == consoleName)) { + stdOut << '\n' << e.fullMessage(); + clear(buffer); + } + } + } + stdOut << '\n'; +} + + +#if defined(XP_MAC) && !defined(XP_MAC_MPW) +int main(int argc, char **argv) +{ + initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv); +#else +int main(int , char **) +{ +#endif + + readEvalPrint(stdin, world); + + return 0; + // return ProcessArgs(argv + 1, argc - 1); +} diff --git a/mozilla/js2/tests/js/calls.js b/mozilla/js2/tests/js/calls.js new file mode 100644 index 00000000000..f0ce431b8d8 --- /dev/null +++ b/mozilla/js2/tests/js/calls.js @@ -0,0 +1,85 @@ + +load("verify.js"); + + +function f1(a = 1) { return a; } + +function f2(a, b = 1) { return a + b; } + +function f3(a, b = 1, c = 2) { return a + b + c; } + +function f4(a, b, c) { return a + b + c; } + + + +function f5(| a) { return a; } + +function f6(| a = 1) { return a; } + +function f7(| 'q' a = 1) { return a; } + + +function f8(a,| b) { return a + b; } + +function f9(a,| 'q' b) { return a + b; } + +function f10(a,| 'q' b = 1) { return a + b; } + + +function f11(a, b, c, ...) { return a + b + c; } + +function f12(a, b, c, ...d) { return a + b + c + d[0]; } + +function f13(a, b, c, ...d) { return a + b + c + d[0] + d[1]; } + + +function f14(| a, b, c) { return a + b - c; } + +function f15(| a, b = 2, c) { return a + b - c; } + + + +verify( f1(), 1); +verify( f1(2), 2); + +verify( f2(1), 2); +verify( f2(1,2), 3); + +verify( f3(1), 4); +verify( f3(1,2), 5); +verify( f3(1,2,3), 6); + +verify( f4(1,2,3), 6); + + +verify( f5(a:1), 1); + +verify( f6(), 1); +verify( f6(a:2), 2); + +verify( f7(a:1), 1); +verify( f7(q:1), 1); +verify( f7(), 1); + +verify( f8(1, b:2), 3); + +verify( f9(1, b:1), 2); +verify( f9(1, q:1), 2); + +verify( f10(1), 2); +verify( f10(1, b:2), 3); + +verify( f11(1, 2, 3), 6); + +verify( f12(1, 2, 3, 4), 10); +verify( f12(1, 2, 3, 4, 5), 10); + +verify( f13(1, 2, 3, 4, 5), 15); +verify( f13(1, 2, 3, 4, 5, 6), 15); + +verify( f14(a:4, b:2, c:3), 3); +verify( f14(c:3, b:2, a:4), 3); +verify( f14(b:2, a:4, c:3), 3); + +verify( f15(a:4, c:3), 3); + diff --git a/mozilla/js2/tests/js/class.xml b/mozilla/js2/tests/js/class.xml new file mode 100644 index 00000000000..fcdfa451c3e --- /dev/null +++ b/mozilla/js2/tests/js/class.xml @@ -0,0 +1,81 @@ + + + + + RETURN R0 + + + + + + GENERIC_BINARY_OP R3, Add, R1, R2 + SET_SLOT R0, 0, R3 + RETURN_VOID + + + + + + + GET_STATIC R1, "D", 1 + BIND_THIS R2, R0, R1 + CALL R3, R2, () + RETURN R0 + + + + + NEW_CLASS R2, "E" + GET_STATIC R3, "E", 1 + BIND_THIS R4, R2, R3 + CALL R1, R4, () + LOAD_IMMEDIATE R2, 1 + LOAD_IMMEDIATE R3, 4 + GET_METHOD R4, R1, 0 + CALL R5, R4, (R2, R3) + GET_SLOT R2, R1, 0 + LOAD_NAME R1, "print" + CALL R1, R1, (R2) + RETURN_VOID + + + + + + GET_CLOSURE R2, 0 + GET_SLOT R3, R2, 1 + GENERIC_BINARY_OP R3, Add, R3, R1 + RETURN R3 + + + + + NEW_CLOSURE R2, "anon_1" + LOAD_IMMEDIATE R3, 1 + CALL R3, R2, (R3) + RETURN R3 + + + diff --git a/mozilla/js2/tests/js/classes.js b/mozilla/js2/tests/js/classes.js new file mode 100644 index 00000000000..1e884b4b6b3 --- /dev/null +++ b/mozilla/js2/tests/js/classes.js @@ -0,0 +1,28 @@ +class A { + static var x = 0; + + static function f() + { + return A.x++; + } +} + +class Point3D { + var x = 0, y = 0, z = 0; + + function set(x, y, z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + function setX(x) { this.x = x; } + function getX() { return this.x; } + + function setY(y) { this.y = y; } + function getY() { return this.y; } + + function setZ(z) { this.z = z; } + function getZ() { return this.z; } +} diff --git a/mozilla/js2/tests/js/constructors.js b/mozilla/js2/tests/js/constructors.js new file mode 100644 index 00000000000..95db10bce56 --- /dev/null +++ b/mozilla/js2/tests/js/constructors.js @@ -0,0 +1,22 @@ +load("verify.js"); + +class C { + var a:String; + + constructor C(p:String) {this.a = "New "+p} + constructor make(p:String) {this.a = "Make "+p} + static function obtain(p:String):C {return new C(p)} + } + +var c:C = new C("one"); +var d:C = C.C("two"); +var e:C = C.make("three"); +var f:C = C.obtain("four"); + +verify( c.a, "New one" ); +verify( d.a, "New two" ); +verify( e.a, "Make three" ); +verify( f.a, "New four" ); + + + diff --git a/mozilla/js2/tests/js/fields.js b/mozilla/js2/tests/js/fields.js new file mode 100644 index 00000000000..c5bac3cca08 --- /dev/null +++ b/mozilla/js2/tests/js/fields.js @@ -0,0 +1,25 @@ + +load("verify.js"); + +class C { +virtual var x:Integer; +var y:Integer; +} + +class D extends C { +override function set x(a:Integer):Integer {return y = a*2} +} + + + var c:C = new C; + c.x = 5; + +verify(c.x, 5.0); +verify(c.y, NaN); + + var d:D = new D; + d.x = 5; + +verify(d.x, NaN); +verify(d.y, 10.0); + diff --git a/mozilla/js2/tests/js/methods.js b/mozilla/js2/tests/js/methods.js new file mode 100644 index 00000000000..15ff72a85aa --- /dev/null +++ b/mozilla/js2/tests/js/methods.js @@ -0,0 +1,16 @@ + +load("verify.js"); + +class C { + var x:Integer = 3; + function m() {return x} + function n(x) {return x+4} + } + + var c:C = new C; +verify( c.m(), 3 ); // returns 3 +verify( c.n(7), 11 ); // returns 11 + var f:Function = c.m; // f is a zero-argument function with this bound to c +verify( f(), 3 ); // returns 3 + c.x = 8; +verify( f(), 8 ); // returns 8 \ No newline at end of file diff --git a/mozilla/js2/tests/js/statics.js b/mozilla/js2/tests/js/statics.js new file mode 100644 index 00000000000..7845bba6570 --- /dev/null +++ b/mozilla/js2/tests/js/statics.js @@ -0,0 +1,61 @@ + +load("verify.js"); + +class C { + static var v = "Cv"; + static var x = "Cx"; + static var y = "Cy"; + static var z = "Cz"; + } +/* + interface A { + static var x = "Ax"; + static var i = "Ai"; + static var j = "Aj"; + } + + interface B { + static var x = "Bx"; + static var y = "By"; + static var j = "Bj"; + } +*/ + class D extends C implements A, B { + static var v = "Dv"; + } + + + +verify( C.v, "Cv" ); +verify( C.x, "Cx" ); +verify( C.y, "Cy" ); +verify( C.z, "Cz" ); +/* +verify( A.x, "Ax" ); +verify( B.y, "By" ); +*/ + +verify( D.v, "Dv" ); +verify( D.x, "Cx" ); +verify( D.y, "Cy" ); +verify( D.z, "Cz" ); + +/* +verify( D.i, "Ai" ); +*/ + +// verify( D.j; // error because of ambiguity: "Aj" or "Bj"? + +/* +verify( D.A::j, "Aj" ); +verify( D.B::j, "Bj" ); +verify( D.A::x, "Ax" ); +verify( D.A::i, "Ai" ); +*/ + +D.x = 5; +verify( C.x, 5 ); +C.v = 7; +verify( D.v, "Dv" ); +verify( C.v, 7 ); + diff --git a/mozilla/js2/tests/js/verify.js b/mozilla/js2/tests/js/verify.js new file mode 100644 index 00000000000..d408b757f93 --- /dev/null +++ b/mozilla/js2/tests/js/verify.js @@ -0,0 +1,11 @@ +count = 0; + +function verify(a, b) +{ + if ((a == b) || ((b != b) && (a == undefined)) ) + print("Test " + count + " succeeded"); + else + print("Test " + count + " failed, expected " + b + ", got " + a); + count++; +} + diff --git a/mozilla/js2/tools/cpp-xref.pl b/mozilla/js2/tools/cpp-xref.pl new file mode 100644 index 00000000000..b079d35b9d6 --- /dev/null +++ b/mozilla/js2/tools/cpp-xref.pl @@ -0,0 +1,138 @@ +#!/bin/perl +use strict; + +my $dir = shift || "./"; +my @files = get_cpp_files ($dir); +my $file; +my %results; +my $verbose = 0; + +foreach $file (@files) { + process_file ($file); +} + +foreach $file (@files) { + my $c = $results{$file}; + my @keys = sort (keys (%{$c})); + my $key; + + print "$file:\n"; + + if ($verbose) { + foreach $key (@keys) { + if ($key !~ /^HASH/) { + print "\t$key: $c->{$key}\n"; + } + } + } + + if ($c->{"hard_tabs"}) { + print "\tHard Tabs: ", $c->{"hard_tabs"}, "\n"; + } + + if ($c->{"sys_includes"}) { + my $incs = join (", ", @{$c->{"sys_includes"}}); + print "\tSystem Includes: $incs\n"; + } + + if ($c->{"local_includes"}) { + my $incs = join (", ", @{$c->{"local_includes"}}); + print "\tLocal Includes: $incs\n"; + } + + print "\n"; +} + +sub process_file { + my ($filename) = @_; + my %c = {}; + open (FILE, $filename); + + while (my $line = ) { + if ($line =~ /\t/) { + if ($c{"hard_tabs"}) { + ++$c{"hard_tabs"}; + } else { + $c{"hard_tabs"} = 1; + } + } + if ($line =~ /(\/\*|\/\/)\s*-\*-\s*Mode: (\S+)/i) { + # it's an emacs mode line + $c{"mode"} = $2; + if ($line =~ /tab-width: (\d+)/i) { + $c{"tab_width"} = $1; + } + if ($line =~ /indent-tabs-mode: (\S+)/i) { + $c{"tab_mode"} = $1; + } + if ($line =~ /c-basic-offset: (\d+)/i) { + $c{"basic_offset"} = $1; + } + } elsif ($line =~ + /(\*|\/\/)\s*The contents of this file are subject to the (\S+)/i) { + # first line of license + $c{"has_license"} = 1; + $c{"license_comment"} = ($1 eq "*") ? "/**/" : "//"; + $c{"license_type"} = (lc($2) eq "netscape") ? "NPL" : "MPL"; + } elsif ($line =~ /The Original Code is (.*)/i) { + # original code line + $c{"o_code"} = $1; + } elsif ($line =~ /Alternatively, the contents of this file may be used under/i) { + $c{"license_dual"} = 1; + + } elsif ($line =~ /^\#include ([\"<])(\S+)[>\"]/i) { + # include directive + if ($1 eq "\"") { + push (@{$c{"local_includes"}}, $2); + } else { + push (@{$c{"sys_includes"}}, $2); + } + } + } + + $results{$filename} = \%c; +} + +# +# given a directory, return an array of all subdirectories +# +sub get_subdirs { + my ($dir) = @_; + my @subdirs; + + if (!($dir =~ /\/$/)) { + $dir = $dir . "/"; + } + + opendir (DIR, $dir) || die ("couldn't open directory $dir: $!"); + my @contents = readdir(DIR); + closedir(DIR); + + foreach (@contents) { + if ((-d ($dir . $_)) && ($_ ne 'CVS') && ($_ ne '.') && ($_ ne '..')) { + @subdirs[$#subdirs + 1] = $_; + } + } + + return @subdirs; +} + +# +# given a directory, return an array of all the .h and .cpp files. +# +sub get_cpp_files { + my ($subdir) = @_; + my (@file_array, @files); + + opendir (SUBDIR, $subdir) || die ("couldn't open directory $subdir: $!"); + @files = readdir(SUBDIR); + closedir(SUBDIR); + + foreach (@files) { + if ($_ =~ /\.h$|\.cpp$/) { + push (@file_array, $_); + } + } + + return sort(@file_array); +}