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: package com.google.gwt.dev.js.rhino;
042:
043: /**
044: * This is the class that implements the runtime.
045: *
046: * @author Norris Boyd
047: */
048:
049: public class ScriptRuntime {
050:
051: public static double NaN = 0.0d / 0.0;
052:
053: public static String numberToString(double d, int base) {
054: if (d != d)
055: return "NaN";
056: if (d == Double.POSITIVE_INFINITY)
057: return "Infinity";
058: if (d == Double.NEGATIVE_INFINITY)
059: return "-Infinity";
060: if (d == 0.0)
061: return "0";
062:
063: if ((base < 2) || (base > 36)) {
064: throw new Error(Context.getMessage1("msg.bad.radix",
065: Integer.toString(base)));
066: }
067:
068: if (base != 10) {
069: return DToA.JS_dtobasestr(base, d);
070: } else {
071: StringBuffer result = new StringBuffer();
072: DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d);
073: return result.toString();
074: }
075:
076: }
077:
078: /*
079: * Helper function for toNumber, parseInt, and TokenStream.getToken.
080: */
081: static double stringToNumber(String s, int start, int radix) {
082: char digitMax = '9';
083: char lowerCaseBound = 'a';
084: char upperCaseBound = 'A';
085: int len = s.length();
086: if (radix < 10) {
087: digitMax = (char) ('0' + radix - 1);
088: }
089: if (radix > 10) {
090: lowerCaseBound = (char) ('a' + radix - 10);
091: upperCaseBound = (char) ('A' + radix - 10);
092: }
093: int end;
094: double sum = 0.0;
095: for (end = start; end < len; end++) {
096: char c = s.charAt(end);
097: int newDigit;
098: if ('0' <= c && c <= digitMax)
099: newDigit = c - '0';
100: else if ('a' <= c && c < lowerCaseBound)
101: newDigit = c - 'a' + 10;
102: else if ('A' <= c && c < upperCaseBound)
103: newDigit = c - 'A' + 10;
104: else
105: break;
106: sum = sum * radix + newDigit;
107: }
108: if (start == end) {
109: return NaN;
110: }
111: if (sum >= 9007199254740992.0) {
112: if (radix == 10) {
113: /* If we're accumulating a decimal number and the number
114: * is >= 2^53, then the result from the repeated multiply-add
115: * above may be inaccurate. Call Java to get the correct
116: * answer.
117: */
118: try {
119: return Double.valueOf(s.substring(start, end))
120: .doubleValue();
121: } catch (NumberFormatException nfe) {
122: return NaN;
123: }
124: } else if (radix == 2 || radix == 4 || radix == 8
125: || radix == 16 || radix == 32) {
126: /* The number may also be inaccurate for one of these bases.
127: * This happens if the addition in value*radix + digit causes
128: * a round-down to an even least significant mantissa bit
129: * when the first dropped bit is a one. If any of the
130: * following digits in the number (which haven't been added
131: * in yet) are nonzero then the correct action would have
132: * been to round up instead of down. An example of this
133: * occurs when reading the number 0x1000000000000081, which
134: * rounds to 0x1000000000000000 instead of 0x1000000000000100.
135: */
136: BinaryDigitReader bdr = new BinaryDigitReader(radix, s,
137: start, end);
138: int bit;
139: sum = 0.0;
140:
141: /* Skip leading zeros. */
142: do {
143: bit = bdr.getNextBinaryDigit();
144: } while (bit == 0);
145:
146: if (bit == 1) {
147: /* Gather the 53 significant bits (including the leading 1) */
148: sum = 1.0;
149: for (int j = 52; j != 0; j--) {
150: bit = bdr.getNextBinaryDigit();
151: if (bit < 0)
152: return sum;
153: sum = sum * 2 + bit;
154: }
155: /* bit54 is the 54th bit (the first dropped from the mantissa) */
156: int bit54 = bdr.getNextBinaryDigit();
157: if (bit54 >= 0) {
158: double factor = 2.0;
159: int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
160: int bit3;
161:
162: while ((bit3 = bdr.getNextBinaryDigit()) >= 0) {
163: sticky |= bit3;
164: factor *= 2;
165: }
166: sum += bit54 & (bit | sticky);
167: sum *= factor;
168: }
169: }
170: }
171: /* We don't worry about inaccurate numbers for any other base. */
172: }
173: return sum;
174: }
175:
176: /**
177: * For escaping strings printed by object and array literals; not quite
178: * the same as 'escape.'
179: */
180: public static String escapeString(String s) {
181:
182: StringBuffer sb = null;
183:
184: for (int i = 0, L = s.length(); i != L; ++i) {
185: int c = s.charAt(i);
186:
187: if (' ' <= c && c <= '~' && c != '"' && c != '\\') {
188: // an ordinary print character (like C isprint()) and not "
189: // or \ . Note single quote ' is not escaped
190: if (sb != null) {
191: sb.append((char) c);
192: }
193: continue;
194: }
195: if (sb == null) {
196: sb = new StringBuffer(L + 3);
197: sb.append(s);
198: sb.setLength(i);
199: }
200:
201: int escape = -1;
202: switch (c) {
203: case '\b':
204: escape = 'b';
205: break;
206: case '\f':
207: escape = 'f';
208: break;
209: case '\n':
210: escape = 'n';
211: break;
212: case '\r':
213: escape = 'r';
214: break;
215: case '\t':
216: escape = 't';
217: break;
218: case 0xb:
219: escape = 'v';
220: break; // Java lacks \v.
221: case '"':
222: escape = '"';
223: break;
224: case ' ':
225: escape = ' ';
226: break;
227: case '\\':
228: escape = '\\';
229: break;
230: }
231: if (escape >= 0) {
232: // an \escaped sort of character
233: sb.append('\\');
234: sb.append((char) escape);
235: } else {
236: int hexSize;
237: if (c < 256) {
238: // 2-digit hex
239: sb.append("\\x");
240: hexSize = 2;
241: } else {
242: // Unicode.
243: sb.append("\\u");
244: hexSize = 4;
245: }
246: // append hexadecimal form of c left-padded with 0
247: for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
248: int digit = 0xf & (c >> shift);
249: int hc = (digit < 10) ? '0' + digit
250: : 'a' - 10 + digit;
251: sb.append((char) hc);
252: }
253: }
254: }
255:
256: return (sb == null) ? s : sb.toString();
257: }
258:
259: }
|