17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
31 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsLong;
32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
33 import static jdk.nashorn.internal.lookup.Lookup.MH;
34
35 import java.lang.invoke.MethodHandle;
36 import java.lang.invoke.MethodHandles;
37 import java.text.NumberFormat;
38 import java.util.Locale;
39 import jdk.internal.dynalink.linker.GuardedInvocation;
40 import jdk.internal.dynalink.linker.LinkRequest;
41 import jdk.nashorn.internal.objects.annotations.Attribute;
42 import jdk.nashorn.internal.objects.annotations.Constructor;
43 import jdk.nashorn.internal.objects.annotations.Function;
44 import jdk.nashorn.internal.objects.annotations.Property;
45 import jdk.nashorn.internal.objects.annotations.ScriptClass;
46 import jdk.nashorn.internal.objects.annotations.Where;
47 import jdk.nashorn.internal.runtime.JSType;
48 import jdk.nashorn.internal.runtime.PropertyMap;
49 import jdk.nashorn.internal.runtime.ScriptObject;
50 import jdk.nashorn.internal.runtime.ScriptRuntime;
51 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
52
53 /**
54 * ECMA 15.7 Number Objects.
55 *
56 */
57 @ScriptClass("Number")
58 public final class NativeNumber extends ScriptObject {
59
60 static final MethodHandle WRAPFILTER = findWrapFilter();
61
62 /** ECMA 15.7.3.2 largest positive finite value */
63 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
64 public static final double MAX_VALUE = Double.MAX_VALUE;
65
66 /** ECMA 15.7.3.3 smallest positive finite value */
67 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
68 public static final double MIN_VALUE = Double.MIN_VALUE;
69
70 /** ECMA 15.7.3.4 NaN */
71 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
72 public static final double NaN = Double.NaN;
73
74 /** ECMA 15.7.3.5 negative infinity */
75 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
76 public static final double NEGATIVE_INFINITY = Double.NEGATIVE_INFINITY;
77
78 /** ECMA 15.7.3.5 positive infinity */
79 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
80 public static final double POSITIVE_INFINITY = Double.POSITIVE_INFINITY;
305
306
307 /**
308 * ECMA 15.7.4.4 Number.prototype.valueOf ( )
309 *
310 * @param self self reference
311 * @return boxed number value for this Number
312 */
313 @Function(attributes = Attribute.NOT_ENUMERABLE)
314 public static Object valueOf(final Object self) {
315 return getNumberValue(self);
316 }
317
318 /**
319 * Lookup the appropriate method for an invoke dynamic call.
320 * @param request The link request
321 * @param receiver receiver of call
322 * @return Link to be invoked at call site.
323 */
324 public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
325 return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
326 }
327
328 @SuppressWarnings("unused")
329 private static NativeNumber wrapFilter(final Object receiver) {
330 return new NativeNumber(((Number)receiver).doubleValue());
331 }
332
333 private static double getNumberValue(final Object self) {
334 if (self instanceof Number) {
335 return ((Number)self).doubleValue();
336 } else if (self instanceof NativeNumber) {
337 return ((NativeNumber)self).getValue();
338 } else if (self != null && self == Global.instance().getNumberPrototype()) {
339 return 0.0;
340 } else {
341 throw typeError("not.a.number", ScriptRuntime.safeToString(self));
342 }
343 }
344
345 // Exponent of Java "e" or "E" formatter is always 2 digits and zero
346 // padded if needed (e+01, e+00, e+12 etc.) JS expects exponent to contain
347 // exact number of digits e+1, e+0, e+12 etc. Fix the exponent here.
348 //
349 // Additionally, if trimZeros is true, this cuts trailing zeros in the
350 // fraction part for calls to toExponential() with undefined fractionDigits
351 // argument.
352 private static String fixExponent(final String str, final boolean trimZeros) {
361 // check if there are any trailing zeroes we should remove
362
363 int fractionOffset = index;
364 if (trimZeros) {
365 assert fractionOffset > 0;
366 char c = str.charAt(fractionOffset - 1);
367 while (fractionOffset > 1 && (c == '0' || c == '.')) {
368 c = str.charAt(--fractionOffset - 1);
369 }
370
371 }
372 // if anything needs to be done compose a new string
373 if (fractionOffset < index || expPadding == 3) {
374 return str.substring(0, fractionOffset)
375 + str.substring(index, index + 2)
376 + str.substring(index + expPadding);
377 }
378 return str;
379 }
380
381 private static MethodHandle findWrapFilter() {
382 return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
383 }
384 }
|
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
31 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsLong;
32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
33 import static jdk.nashorn.internal.lookup.Lookup.MH;
34
35 import java.lang.invoke.MethodHandle;
36 import java.lang.invoke.MethodHandles;
37 import java.lang.invoke.MethodType;
38 import java.text.NumberFormat;
39 import java.util.Locale;
40 import jdk.internal.dynalink.linker.GuardedInvocation;
41 import jdk.internal.dynalink.linker.LinkRequest;
42 import jdk.nashorn.internal.objects.annotations.Attribute;
43 import jdk.nashorn.internal.objects.annotations.Constructor;
44 import jdk.nashorn.internal.objects.annotations.Function;
45 import jdk.nashorn.internal.objects.annotations.Property;
46 import jdk.nashorn.internal.objects.annotations.ScriptClass;
47 import jdk.nashorn.internal.objects.annotations.Where;
48 import jdk.nashorn.internal.runtime.JSType;
49 import jdk.nashorn.internal.runtime.PropertyMap;
50 import jdk.nashorn.internal.runtime.ScriptObject;
51 import jdk.nashorn.internal.runtime.ScriptRuntime;
52 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
53
54 /**
55 * ECMA 15.7 Number Objects.
56 *
57 */
58 @ScriptClass("Number")
59 public final class NativeNumber extends ScriptObject {
60
61 static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
62 static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
63
64 /** ECMA 15.7.3.2 largest positive finite value */
65 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
66 public static final double MAX_VALUE = Double.MAX_VALUE;
67
68 /** ECMA 15.7.3.3 smallest positive finite value */
69 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
70 public static final double MIN_VALUE = Double.MIN_VALUE;
71
72 /** ECMA 15.7.3.4 NaN */
73 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
74 public static final double NaN = Double.NaN;
75
76 /** ECMA 15.7.3.5 negative infinity */
77 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
78 public static final double NEGATIVE_INFINITY = Double.NEGATIVE_INFINITY;
79
80 /** ECMA 15.7.3.5 positive infinity */
81 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
82 public static final double POSITIVE_INFINITY = Double.POSITIVE_INFINITY;
307
308
309 /**
310 * ECMA 15.7.4.4 Number.prototype.valueOf ( )
311 *
312 * @param self self reference
313 * @return boxed number value for this Number
314 */
315 @Function(attributes = Attribute.NOT_ENUMERABLE)
316 public static Object valueOf(final Object self) {
317 return getNumberValue(self);
318 }
319
320 /**
321 * Lookup the appropriate method for an invoke dynamic call.
322 * @param request The link request
323 * @param receiver receiver of call
324 * @return Link to be invoked at call site.
325 */
326 public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
327 return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER);
328 }
329
330 @SuppressWarnings("unused")
331 private static NativeNumber wrapFilter(final Object receiver) {
332 return new NativeNumber(((Number)receiver).doubleValue());
333 }
334
335 @SuppressWarnings("unused")
336 private static Object protoFilter(final Object object) {
337 return Global.instance().getNumberPrototype();
338 }
339
340 private static double getNumberValue(final Object self) {
341 if (self instanceof Number) {
342 return ((Number)self).doubleValue();
343 } else if (self instanceof NativeNumber) {
344 return ((NativeNumber)self).getValue();
345 } else if (self != null && self == Global.instance().getNumberPrototype()) {
346 return 0.0;
347 } else {
348 throw typeError("not.a.number", ScriptRuntime.safeToString(self));
349 }
350 }
351
352 // Exponent of Java "e" or "E" formatter is always 2 digits and zero
353 // padded if needed (e+01, e+00, e+12 etc.) JS expects exponent to contain
354 // exact number of digits e+1, e+0, e+12 etc. Fix the exponent here.
355 //
356 // Additionally, if trimZeros is true, this cuts trailing zeros in the
357 // fraction part for calls to toExponential() with undefined fractionDigits
358 // argument.
359 private static String fixExponent(final String str, final boolean trimZeros) {
368 // check if there are any trailing zeroes we should remove
369
370 int fractionOffset = index;
371 if (trimZeros) {
372 assert fractionOffset > 0;
373 char c = str.charAt(fractionOffset - 1);
374 while (fractionOffset > 1 && (c == '0' || c == '.')) {
375 c = str.charAt(--fractionOffset - 1);
376 }
377
378 }
379 // if anything needs to be done compose a new string
380 if (fractionOffset < index || expPadding == 3) {
381 return str.substring(0, fractionOffset)
382 + str.substring(index, index + 2)
383 + str.substring(index + expPadding);
384 }
385 return str;
386 }
387
388 private static MethodHandle findOwnMH(final String name, final MethodType type) {
389 return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, name, type);
390 }
391 }
|