001    /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002     *
003     * The contents of this file are subject to the Netscape Public
004     * License Version 1.1 (the "License"); you may not use this file
005     * except in compliance with the License. You may obtain a copy of
006     * the License at http://www.mozilla.org/NPL/
007     *
008     * Software distributed under the License is distributed on an "AS
009     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
010     * implied. See the License for the specific language governing
011     * rights and limitations under the License.
012     *
013     * The Original Code is Rhino code, released
014     * May 6, 1999.
015     *
016     * The Initial Developer of the Original Code is Netscape
017     * Communications Corporation.  Portions created by Netscape are
018     * Copyright (C) 1997-2000 Netscape Communications Corporation. All
019     * Rights Reserved.
020     *
021     * Contributor(s):
022     * Patrick Beard
023     * Norris Boyd
024     * Igor Bukanov
025     * Roger Lawrence
026     * Frank Mitchell
027     * Andrew Wason
028     *
029     * Alternatively, the contents of this file may be used under the
030     * terms of the GNU Public License (the "GPL"), in which case the
031     * provisions of the GPL are applicable instead of those above.
032     * If you wish to allow use of your version of this file only
033     * under the terms of the GPL and not to allow others to use your
034     * version of this file under the NPL, indicate your decision by
035     * deleting the provisions above and replace them with the notice
036     * and other provisions required by the GPL.  If you do not delete
037     * the provisions above, a recipient may use your version of this
038     * file under either the NPL or the GPL.
039     */
040    // Modified by Google
041    
042    package com.google.gwt.dev.js.rhino;
043    
044    /**
045     * This is the class that implements the runtime.
046     */
047    
048    public class ScriptRuntime {
049    
050        public static double NaN = 0.0d / 0.0;
051    
052        /*
053         * Helper function for toNumber, parseInt, and TokenStream.getToken.
054         */
055        static double stringToNumber(String s, int start, int radix) {
056            char digitMax = '9';
057            char lowerCaseBound = 'a';
058            char upperCaseBound = 'A';
059            int len = s.length();
060            if (radix < 10) {
061                digitMax = (char) ('0' + radix - 1);
062            }
063            if (radix > 10) {
064                lowerCaseBound = (char) ('a' + radix - 10);
065                upperCaseBound = (char) ('A' + radix - 10);
066            }
067            int end;
068            double sum = 0.0;
069            for (end=start; end < len; end++) {
070                char c = s.charAt(end);
071                int newDigit;
072                if ('0' <= c && c <= digitMax)
073                    newDigit = c - '0';
074                else if ('a' <= c && c < lowerCaseBound)
075                    newDigit = c - 'a' + 10;
076                else if ('A' <= c && c < upperCaseBound)
077                    newDigit = c - 'A' + 10;
078                else
079                    break;
080                sum = sum*radix + newDigit;
081            }
082            if (start == end) {
083                return NaN;
084            }
085            if (sum >= 9007199254740992.0) {
086                if (radix == 10) {
087                    /* If we're accumulating a decimal number and the number
088                     * is >= 2^53, then the result from the repeated multiply-add
089                     * above may be inaccurate.  Call Java to get the correct
090                     * answer.
091                     */
092                    try {
093                        return Double.valueOf(s.substring(start, end)).doubleValue();
094                    } catch (NumberFormatException nfe) {
095                        return NaN;
096                    }
097                } else if (radix == 2 || radix == 4 || radix == 8 ||
098                           radix == 16 || radix == 32)
099                {
100                    /* The number may also be inaccurate for one of these bases.
101                     * This happens if the addition in value*radix + digit causes
102                     * a round-down to an even least significant mantissa bit
103                     * when the first dropped bit is a one.  If any of the
104                     * following digits in the number (which haven't been added
105                     * in yet) are nonzero then the correct action would have
106                     * been to round up instead of down.  An example of this
107                     * occurs when reading the number 0x1000000000000081, which
108                     * rounds to 0x1000000000000000 instead of 0x1000000000000100.
109                     */
110                    BinaryDigitReader bdr = new BinaryDigitReader(radix, s, start, end);
111                    int bit;
112                    sum = 0.0;
113    
114                    /* Skip leading zeros. */
115                    do {
116                        bit = bdr.getNextBinaryDigit();
117                    } while (bit == 0);
118    
119                    if (bit == 1) {
120                        /* Gather the 53 significant bits (including the leading 1) */
121                        sum = 1.0;
122                        for (int j = 52; j != 0; j--) {
123                            bit = bdr.getNextBinaryDigit();
124                            if (bit < 0)
125                                return sum;
126                            sum = sum*2 + bit;
127                        }
128                        /* bit54 is the 54th bit (the first dropped from the mantissa) */
129                        int bit54 = bdr.getNextBinaryDigit();
130                        if (bit54 >= 0) {
131                            double factor = 2.0;
132                            int sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
133                            int bit3;
134    
135                            while ((bit3 = bdr.getNextBinaryDigit()) >= 0) {
136                                sticky |= bit3;
137                                factor *= 2;
138                            }
139                            sum += bit54 & (bit | sticky);
140                            sum *= factor;
141                        }
142                    }
143                }
144                /* We don't worry about inaccurate numbers for any other base. */
145            }
146            return sum;
147        }
148    
149    }