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); +}