Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duk_numconv.h File Reference

Go to the source code of this file.

Macros

#define DUK_N2S_FLAG_FIXED_FORMAT   (1 << 0)
 
#define DUK_N2S_FLAG_FORCE_EXP   (1 << 1)
 
#define DUK_N2S_FLAG_NO_ZERO_PAD   (1 << 2)
 
#define DUK_N2S_FLAG_FRACTION_DIGITS   (1 << 3)
 
#define DUK_S2N_MAX_EXPONENT   1000000000
 
#define DUK_S2N_FLAG_TRIM_WHITE   (1 << 0)
 
#define DUK_S2N_FLAG_ALLOW_EXP   (1 << 1)
 
#define DUK_S2N_FLAG_ALLOW_GARBAGE   (1 << 2)
 
#define DUK_S2N_FLAG_ALLOW_PLUS   (1 << 3)
 
#define DUK_S2N_FLAG_ALLOW_MINUS   (1 << 4)
 
#define DUK_S2N_FLAG_ALLOW_INF   (1 << 5)
 
#define DUK_S2N_FLAG_ALLOW_FRAC   (1 << 6)
 
#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC   (1 << 7)
 
#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC   (1 << 8)
 
#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO   (1 << 9)
 
#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO   (1 << 10)
 
#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT   (1 << 11)
 
#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT   (1 << 12)
 

Functions

DUK_INTERNAL_DECL void duk_numconv_stringify (duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags)
 
DUK_INTERNAL_DECL void duk_numconv_parse (duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags)
 

Macro Definition Documentation

◆ DUK_N2S_FLAG_FIXED_FORMAT

#define DUK_N2S_FLAG_FIXED_FORMAT   (1 << 0)

Definition at line 12 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_N2S_FLAG_FORCE_EXP

#define DUK_N2S_FLAG_FORCE_EXP   (1 << 1)

Definition at line 15 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_N2S_FLAG_FRACTION_DIGITS

#define DUK_N2S_FLAG_FRACTION_DIGITS   (1 << 3)

Definition at line 28 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_N2S_FLAG_NO_ZERO_PAD

#define DUK_N2S_FLAG_NO_ZERO_PAD   (1 << 2)

Definition at line 22 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT

#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT   (1 << 11)

Definition at line 76 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT

#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT   (1 << 12)

Definition at line 81 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO

#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO   (1 << 9)

Definition at line 68 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_EMPTY_FRAC

#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC   (1 << 8)

Definition at line 65 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_EXP

#define DUK_S2N_FLAG_ALLOW_EXP   (1 << 1)

Definition at line 44 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_FRAC

#define DUK_S2N_FLAG_ALLOW_FRAC   (1 << 6)

Definition at line 59 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_GARBAGE

#define DUK_S2N_FLAG_ALLOW_GARBAGE   (1 << 2)

Definition at line 47 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_INF

#define DUK_S2N_FLAG_ALLOW_INF   (1 << 5)

Definition at line 56 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_LEADING_ZERO

#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO   (1 << 10)

Definition at line 71 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_MINUS

#define DUK_S2N_FLAG_ALLOW_MINUS   (1 << 4)

Definition at line 53 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_NAKED_FRAC

#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC   (1 << 7)

Definition at line 62 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_ALLOW_PLUS

#define DUK_S2N_FLAG_ALLOW_PLUS   (1 << 3)

Definition at line 50 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_FLAG_TRIM_WHITE

#define DUK_S2N_FLAG_TRIM_WHITE   (1 << 0)

Definition at line 41 of file duktape-1.8.0/src-separate/duk_numconv.h.

◆ DUK_S2N_MAX_EXPONENT

#define DUK_S2N_MAX_EXPONENT   1000000000

Definition at line 38 of file duktape-1.8.0/src-separate/duk_numconv.h.

Function Documentation

◆ duk_numconv_parse()

DUK_INTERNAL_DECL void duk_numconv_parse ( duk_context * ctx,
duk_small_int_t radix,
duk_small_uint_t flags )

Definition at line 76728 of file duktape-1.5.2/src-noline/duktape.c.

76745 {
76746 duk_hthread *thr = (duk_hthread *) ctx;
76747 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
76748 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
76749 duk_double_t res;
76750 duk_hstring *h_str;
76751 duk_small_int_t expt;
76752 duk_small_int_t expt_neg;
76753 duk_small_int_t expt_adj;
76754 duk_small_int_t neg;
76755 duk_small_int_t dig;
76756 duk_small_int_t dig_whole;
76757 duk_small_int_t dig_lzero;
76758 duk_small_int_t dig_frac;
76759 duk_small_int_t dig_expt;
76760 duk_small_int_t dig_prec;
76761 const duk__exp_limits *explim;
76762 const duk_uint8_t *p;
76763 duk_small_int_t ch;
76764
76765 /* This seems to waste a lot of stack frame entries, but good compilers
76766 * will compute these as needed below. Some of these initial flags are
76767 * also modified in the code below, so they can't all be removed.
76768 */
76769 duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
76770 duk_small_int_t allow_expt = (flags & DUK_S2N_FLAG_ALLOW_EXP);
76771 duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
76772 duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
76773 duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
76774 duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
76775 duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
76776 duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
76777 duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
76778 duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
76779 duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
76780 duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
76781 duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
76782
76783 DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
76784 (duk_tval *) duk_get_tval(ctx, -1),
76785 (long) radix, (unsigned long) flags));
76786
76787 DUK_ASSERT(radix >= 2 && radix <= 36);
76789
76790 /*
76791 * Preliminaries: trim, sign, Infinity check
76792 *
76793 * We rely on the interned string having a NUL terminator, which will
76794 * cause a parse failure wherever it is encountered. As a result, we
76795 * don't need separate pointer checks.
76796 *
76797 * There is no special parsing for 'NaN' in the specification although
76798 * 'Infinity' (with an optional sign) is allowed in some contexts.
76799 * Some contexts allow plus/minus sign, while others only allow the
76800 * minus sign (like JSON.parse()).
76801 *
76802 * Automatic hex number detection (leading '0x' or '0X') and octal
76803 * number detection (leading '0' followed by at least one octal digit)
76804 * is done here too.
76805 */
76806
76807 if (trim_white) {
76808 /* Leading / trailing whitespace is sometimes accepted and
76809 * sometimes not. After white space trimming, all valid input
76810 * characters are pure ASCII.
76811 */
76812 duk_trim(ctx, -1);
76813 }
76814 h_str = duk_require_hstring(ctx, -1);
76815 DUK_ASSERT(h_str != NULL);
76816 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
76817
76818 neg = 0;
76819 ch = *p;
76820 if (ch == (duk_small_int_t) '+') {
76821 if (!allow_plus) {
76822 DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
76823 goto parse_fail;
76824 }
76825 p++;
76826 } else if (ch == (duk_small_int_t) '-') {
76827 if (!allow_minus) {
76828 DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
76829 goto parse_fail;
76830 }
76831 p++;
76832 neg = 1;
76833 }
76834
76835 ch = *p;
76836 if (allow_infinity && ch == (duk_small_int_t) 'I') {
76837 /* Don't check for Infinity unless the context allows it.
76838 * 'Infinity' is a valid integer literal in e.g. base-36:
76839 *
76840 * parseInt('Infinity', 36)
76841 * 1461559270678
76842 */
76843
76844 const duk_uint8_t *q;
76845
76846 /* borrow literal Infinity from builtin string */
76847 q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
76848 if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
76849 if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
76850 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
76851 goto parse_fail;
76852 } else {
76853 res = DUK_DOUBLE_INFINITY;
76854 goto negcheck_and_ret;
76855 }
76856 }
76857 }
76858 if (ch == (duk_small_int_t) '0') {
76859 duk_small_int_t detect_radix = 0;
76860 ch = p[1];
76861 if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
76862 DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
76863 detect_radix = 16;
76864 allow_empty = 0; /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
76865 p += 2;
76866 } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
76867 DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
76868 detect_radix = 8;
76869 allow_empty = 1; /* interpret e.g. '09' as '0', not NaN */
76870 p += 1;
76871 }
76872 if (detect_radix > 0) {
76873 radix = detect_radix;
76874 allow_expt = 0;
76875 allow_frac = 0;
76876 allow_naked_frac = 0;
76877 allow_empty_frac = 0;
76878 allow_leading_zero = 1; /* allow e.g. '0x0009' and '00077' */
76879 }
76880 }
76881
76882 /*
76883 * Scan number and setup for Dragon4.
76884 *
76885 * The fast path case is detected during setup: an integer which
76886 * can be converted without rounding, no net exponent. The fast
76887 * path could be implemented as a separate scan, but may not really
76888 * be worth it: the multiplications for building 'f' are not
76889 * expensive when 'f' is small.
76890 *
76891 * The significand ('f') must contain enough bits of (apparent)
76892 * accuracy, so that Dragon4 will generate enough binary output digits.
76893 * For decimal numbers, this means generating a 20-digit significand,
76894 * which should yield enough practical accuracy to parse IEEE doubles.
76895 * In fact, the Ecmascript specification explicitly allows an
76896 * implementation to treat digits beyond 20 as zeroes (and even
76897 * to round the 20th digit upwards). For non-decimal numbers, the
76898 * appropriate number of digits has been precomputed for comparable
76899 * accuracy.
76900 *
76901 * Digit counts:
76902 *
76903 * [ dig_lzero ]
76904 * |
76905 * .+-..---[ dig_prec ]----.
76906 * | || |
76907 * 0000123.456789012345678901234567890e+123456
76908 * | | | | | |
76909 * `--+--' `------[ dig_frac ]-------' `-+--'
76910 * | |
76911 * [ dig_whole ] [ dig_expt ]
76912 *
76913 * dig_frac and dig_expt are -1 if not present
76914 * dig_lzero is only computed for whole number part
76915 *
76916 * Parsing state
76917 *
76918 * Parsing whole part dig_frac < 0 AND dig_expt < 0
76919 * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
76920 * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
76921 *
76922 * Note: in case we hit an implementation limit (like exponent range),
76923 * we should throw an error, NOT return NaN or Infinity. Even with
76924 * very large exponent (or significand) values the final result may be
76925 * finite, so NaN/Infinity would be incorrect.
76926 */
76927
76928 duk__bi_set_small(&nc_ctx->f, 0);
76929 dig_prec = 0;
76930 dig_lzero = 0;
76931 dig_whole = 0;
76932 dig_frac = -1;
76933 dig_expt = -1;
76934 expt = 0;
76935 expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
76936 expt_neg = 0;
76937 for (;;) {
76938 ch = *p++;
76939
76940 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
76941 "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
76942 (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
76943 (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
76944 (long) dig_expt, (long) dig_lzero, (long) dig_prec));
76945 DUK__BI_PRINT("f", &nc_ctx->f);
76946
76947 /* Most common cases first. */
76948 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
76949 dig = (int) ch - '0' + 0;
76950 } else if (ch == (duk_small_int_t) '.') {
76951 /* A leading digit is not required in some cases, e.g. accept ".123".
76952 * In other cases (JSON.parse()) a leading digit is required. This
76953 * is checked for after the loop.
76954 */
76955 if (dig_frac >= 0 || dig_expt >= 0) {
76956 if (allow_garbage) {
76957 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
76958 break;
76959 } else {
76960 DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
76961 goto parse_fail;
76962 }
76963 }
76964
76965 if (!allow_frac) {
76966 /* Some contexts don't allow fractions at all; this can't be a
76967 * post-check because the state ('f' and expt) would be incorrect.
76968 */
76969 if (allow_garbage) {
76970 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
76971 break;
76972 } else {
76973 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
76974 }
76975 }
76976
76977 DUK_DDD(DUK_DDDPRINT("start fraction part"));
76978 dig_frac = 0;
76979 continue;
76980 } else if (ch == (duk_small_int_t) 0) {
76981 DUK_DDD(DUK_DDDPRINT("NUL termination"));
76982 break;
76983 } else if (allow_expt && dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
76984 /* Note: we don't parse back exponent notation for anything else
76985 * than radix 10, so this is not an ambiguous check (e.g. hex
76986 * exponent values may have 'e' either as a significand digit
76987 * or as an exponent separator).
76988 *
76989 * If the exponent separator occurs twice, 'e' will be interpreted
76990 * as a digit (= 14) and will be rejected as an invalid decimal
76991 * digit.
76992 */
76993
76994 DUK_DDD(DUK_DDDPRINT("start exponent part"));
76995
76996 /* Exponent without a sign or with a +/- sign is accepted
76997 * by all call sites (even JSON.parse()).
76998 */
76999 ch = *p;
77000 if (ch == (duk_small_int_t) '-') {
77001 expt_neg = 1;
77002 p++;
77003 } else if (ch == (duk_small_int_t) '+') {
77004 p++;
77005 }
77006 dig_expt = 0;
77007 continue;
77008 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
77009 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
77010 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
77011 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
77012 } else {
77013 dig = 255; /* triggers garbage digit check below */
77014 }
77015 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
77016
77017 if (dig >= radix) {
77018 if (allow_garbage) {
77019 DUK_DDD(DUK_DDDPRINT("garbage termination"));
77020 break;
77021 } else {
77022 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
77023 goto parse_fail;
77024 }
77025 }
77026
77027 if (dig_expt < 0) {
77028 /* whole or fraction digit */
77029
77030 if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77031 /* significant from precision perspective */
77032
77033 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
77034 if (f_zero && dig == 0) {
77035 /* Leading zero is not counted towards precision digits; not
77036 * in the integer part, nor in the fraction part.
77037 */
77038 if (dig_frac < 0) {
77039 dig_lzero++;
77040 }
77041 } else {
77042 /* XXX: join these ops (multiply-accumulate), but only if
77043 * code footprint decreases.
77044 */
77045 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
77046 duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
77047 dig_prec++;
77048 }
77049 } else {
77050 /* Ignore digits beyond a radix-specific limit, but note them
77051 * in expt_adj.
77052 */
77053 expt_adj++;
77054 }
77055
77056 if (dig_frac >= 0) {
77057 dig_frac++;
77058 expt_adj--;
77059 } else {
77060 dig_whole++;
77061 }
77062 } else {
77063 /* exponent digit */
77064
77065 expt = expt * radix + dig;
77066 if (expt > DUK_S2N_MAX_EXPONENT) {
77067 /* impose a reasonable exponent limit, so that exp
77068 * doesn't need to get tracked using a bigint.
77069 */
77070 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
77071 goto parse_explimit_error;
77072 }
77073 dig_expt++;
77074 }
77075 }
77076
77077 /* Leading zero. */
77078
77079 if (dig_lzero > 0 && dig_whole > 1) {
77080 if (!allow_leading_zero) {
77081 DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
77082 goto parse_fail;
77083 }
77084 }
77085
77086 /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
77087
77088 if (dig_whole == 0) {
77089 if (dig_frac == 0) {
77090 /* "." is not accepted in any format */
77091 DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
77092 goto parse_fail;
77093 } else if (dig_frac > 0) {
77094 /* ".123" */
77095 if (!allow_naked_frac) {
77096 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
77097 "leading integer digit(s)"));
77098 goto parse_fail;
77099 }
77100 } else {
77101 /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
77102 if (!allow_empty) {
77103 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
77104 goto parse_fail;
77105 }
77106 }
77107 } else {
77108 if (dig_frac == 0) {
77109 /* "123." is allowed in some formats */
77110 if (!allow_empty_frac) {
77111 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
77112 goto parse_fail;
77113 }
77114 } else if (dig_frac > 0) {
77115 /* "123.456" */
77116 ;
77117 } else {
77118 /* "123" */
77119 ;
77120 }
77121 }
77122
77123 /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
77124 * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
77125 */
77126
77127 if (dig_expt == 0) {
77128 if (!allow_garbage) {
77129 DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
77130 goto parse_fail;
77131 }
77132 DUK_ASSERT(expt == 0);
77133 }
77134
77135 if (expt_neg) {
77136 expt = -expt;
77137 }
77138 DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
77139 (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
77140 expt += expt_adj;
77141
77142 /* Fast path check. */
77143
77144 if (nc_ctx->f.n <= 1 && /* 32-bit value */
77145 expt == 0 /* no net exponent */) {
77146 /* Fast path is triggered for no exponent and also for balanced exponent
77147 * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
77148 * zero sign.
77149 */
77150
77151 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
77152 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
77153 if (nc_ctx->f.n == 1) {
77154 res = (double) nc_ctx->f.v[0];
77155 } else {
77156 res = 0.0;
77157 }
77158 goto negcheck_and_ret;
77159 }
77160
77161 /* Significand ('f') padding. */
77162
77163 while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77164 /* Pad significand with "virtual" zero digits so that Dragon4 will
77165 * have enough (apparent) precision to work with.
77166 */
77167 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
77168 duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
77169 DUK__BI_PRINT("f", &nc_ctx->f);
77170 expt--;
77171 dig_prec++;
77172 }
77173
77174 DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
77175
77176 /* Detect zero special case. */
77177
77178 if (nc_ctx->f.n == 0) {
77179 /* This may happen even after the fast path check, if exponent is
77180 * not balanced (e.g. "0e1"). Remember to respect zero sign.
77181 */
77182 DUK_DDD(DUK_DDDPRINT("significand is zero"));
77183 res = 0.0;
77184 goto negcheck_and_ret;
77185 }
77186
77187
77188 /* Quick reject of too large or too small exponents. This check
77189 * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
77190 * so zero check must be above.
77191 */
77192
77193 explim = &duk__str2num_exp_limits[radix - 2];
77194 if (expt > explim->upper) {
77195 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
77197 goto negcheck_and_ret;
77198 } else if (expt < explim->lower) {
77199 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
77200 res = (duk_double_t) 0.0;
77201 goto negcheck_and_ret;
77202 }
77203
77204 nc_ctx->is_s2n = 1;
77205 nc_ctx->e = expt;
77206 nc_ctx->b = radix;
77207 nc_ctx->B = 2;
77208 nc_ctx->is_fixed = 1;
77209 nc_ctx->abs_pos = 0;
77210 nc_ctx->req_digits = 53 + 1;
77211
77212 DUK__BI_PRINT("f", &nc_ctx->f);
77213 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
77214
77215 /*
77216 * Dragon4 slow path (binary) digit generation.
77217 * An extra digit is generated for rounding.
77218 */
77219
77220 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
77221
77222 DUK_DDD(DUK_DDDPRINT("after prepare:"));
77223 DUK__BI_PRINT("r", &nc_ctx->r);
77224 DUK__BI_PRINT("s", &nc_ctx->s);
77225 DUK__BI_PRINT("mp", &nc_ctx->mp);
77226 DUK__BI_PRINT("mm", &nc_ctx->mm);
77227
77228 duk__dragon4_scale(nc_ctx);
77229
77230 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
77231 DUK__BI_PRINT("r", &nc_ctx->r);
77232 DUK__BI_PRINT("s", &nc_ctx->s);
77233 DUK__BI_PRINT("mp", &nc_ctx->mp);
77234 DUK__BI_PRINT("mm", &nc_ctx->mm);
77235
77236 duk__dragon4_generate(nc_ctx);
77237
77238 DUK_ASSERT(nc_ctx->count == 53 + 1);
77239
77240 /*
77241 * Convert binary digits into an IEEE double. Need to handle
77242 * denormals and rounding correctly.
77243 */
77244
77245 duk__dragon4_ctx_to_double(nc_ctx, &res);
77246 goto negcheck_and_ret;
77247
77248 negcheck_and_ret:
77249 if (neg) {
77250 res = -res;
#define DUK_HSTRING_GET_DATA(x)
DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z)
#define DUK_S2N_FLAG_ALLOW_FRAC
DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z)
#define DUK_S2N_FLAG_ALLOW_MINUS
#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC
DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v)
DUK_LOCAL int duk__bi_is_zero(duk__bigint *x)
DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[]
#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC
#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT
#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT
DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t)
DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index)
DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x)
DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx)
DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[]
#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO
#define DUK__BI_PRINT(name, x)
#define DUK_S2N_FLAG_ALLOW_PLUS
#define DUK_S2N_FLAG_ALLOW_INF
DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx)
DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx)
#define DUK_S2N_FLAG_TRIM_WHITE
DUK_INTERNAL_DECL duk_hstring * duk_require_hstring(duk_context *ctx, duk_idx_t index)
#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO
#define DUK_HTHREAD_STRING_INFINITY(thr)
#define DUK_S2N_FLAG_ALLOW_EXP
#define DUK_S2N_FLAG_ALLOW_GARBAGE
DUK_INTERNAL_DECL duk_tval * duk_get_tval(duk_context *ctx, duk_idx_t index)
#define NULL
Definition gmacros.h:924
duk_uint32_t v[DUK__BI_MAX_PARTS]

References duk__numconv_stringify_ctx::abs_pos, duk__numconv_stringify_ctx::b, duk__numconv_stringify_ctx::B, duk__numconv_stringify_ctx::count, duk__bi_add_small(), duk__bi_is_zero(), duk__bi_mul_small(), duk__bi_mul_small_copy(), DUK__BI_PRINT, duk__bi_set_small(), duk__dragon4_ctx_to_double(), duk__dragon4_generate(), duk__dragon4_prepare(), duk__dragon4_scale(), duk__str2num_digits_for_radix, duk__str2num_exp_limits, DUK_ASSERT, DUK_DDD, DUK_DDDPRINT, DUK_DOUBLE_INFINITY, DUK_ERROR_RANGE, duk_get_tval(), DUK_HSTRING_GET_DATA, DUK_HTHREAD_STRING_INFINITY, duk_pop(), duk_push_nan(), duk_push_number(), duk_require_hstring(), DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT, DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT, DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO, DUK_S2N_FLAG_ALLOW_EMPTY_FRAC, DUK_S2N_FLAG_ALLOW_EXP, DUK_S2N_FLAG_ALLOW_FRAC, DUK_S2N_FLAG_ALLOW_GARBAGE, DUK_S2N_FLAG_ALLOW_INF, DUK_S2N_FLAG_ALLOW_LEADING_ZERO, DUK_S2N_FLAG_ALLOW_MINUS, DUK_S2N_FLAG_ALLOW_NAKED_FRAC, DUK_S2N_FLAG_ALLOW_PLUS, DUK_S2N_FLAG_TRIM_WHITE, DUK_S2N_MAX_EXPONENT, DUK_STRNCMP, duk_trim(), duk__numconv_stringify_ctx::e, duk__numconv_stringify_ctx::f, duk__numconv_stringify_ctx::is_fixed, duk__numconv_stringify_ctx::is_s2n, duk__numconv_stringify_ctx::k, duk__numconv_stringify_ctx::mm, duk__numconv_stringify_ctx::mp, duk__bigint::n, NULL, duk__numconv_stringify_ctx::r, duk__numconv_stringify_ctx::req_digits, duk__numconv_stringify_ctx::s, duk__numconv_stringify_ctx::t1, duk__exp_limits::upper, and duk__bigint::v.

Referenced by duk__dec_number(), duk__tonumber_string_raw(), duk_bi_global_object_parse_float(), duk_bi_global_object_parse_int(), and duk_lexer_parse_js_input_element().

◆ duk_numconv_stringify()

DUK_INTERNAL_DECL void duk_numconv_stringify ( duk_context * ctx,
duk_small_int_t radix,
duk_small_int_t digits,
duk_small_uint_t flags )

Definition at line 76525 of file duktape-1.5.2/src-noline/duktape.c.

76528 : %08lx %08lx",
76529 (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
76530 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
76531
76532 *x = DUK_DBLUNION_GET_DOUBLE(&u);
76533}
76534
76535/*
76536 * Exposed number-to-string API
76537 *
76538 * Input: [ number ]
76539 * Output: [ string ]
76540 */
76541
76542DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
76543 duk_double_t x;
76544 duk_small_int_t c;
76545 duk_small_int_t neg;
76546 duk_uint32_t uval;
76547 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
76548 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
76549
76550 x = (duk_double_t) duk_require_number(ctx, -1);
76551 duk_pop(ctx);
76552
76553 /*
76554 * Handle special cases (NaN, infinity, zero).
76555 */
76556
76557 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
76558 if (DUK_SIGNBIT((double) x)) {
76559 x = -x;
76560 neg = 1;
76561 } else {
76562 neg = 0;
76563 }
76564
76565 /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
76566 DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
76567
76568 if (c == DUK_FP_NAN) {
76569 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
76570 return;
76571 } else if (c == DUK_FP_INFINITE) {
76572 if (neg) {
76573 /* -Infinity */
76574 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
76575 } else {
76576 /* Infinity */
76577 duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
76578 }
76579 return;
76580 } else if (c == DUK_FP_ZERO) {
76581 /* We can't shortcut zero here if it goes through special formatting
76582 * (such as forced exponential notation).
76583 */
76584 ;
76585 }
76586
76587 /*
76588 * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
76589 * specially, as they're very likely for embedded programs. This
76590 * is now done for all radix values. We must be careful not to use
76591 * the fast path when special formatting (e.g. forced exponential)
76592 * is in force.
76593 *
76594 * XXX: could save space by supporting radix 10 only and using
76595 * sprintf "%lu" for the fast path and for exponent formatting.
76596 */
76597
76598 uval = (unsigned int) x;
76599 if (((double) uval) == x && /* integer number in range */
76600 flags == 0) { /* no special formatting */
76601 /* use bigint area as a temp */
76602 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
76603 duk_uint8_t *p = buf;
76604
76605 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
76606 if (neg && uval != 0) {
76607 /* no negative sign for zero */
76608 *p++ = (duk_uint8_t) '-';
76609 }
76610 p += duk__dragon4_format_uint32(p, uval, radix);
76611 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
76612 return;
76613 }
76614
76615 /*
76616 * Dragon4 setup.
76617 *
76618 * Convert double from IEEE representation for conversion;
76619 * normal finite values have an implicit leading 1-bit. The
76620 * slow path algorithm doesn't handle zero, so zero is special
76621 * cased here but still creates a valid nc_ctx, and goes
76622 * through normal formatting in case special formatting has
76623 * been requested (e.g. forced exponential format: 0 -> "0e+0").
76624 */
76625
76626 /* Would be nice to bulk clear the allocation, but the context
76627 * is 1-2 kilobytes and nothing should rely on it being zeroed.
76628 */
76629#if 0
76630 DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
76631#endif
76632
76633 nc_ctx->is_s2n = 0;
76634 nc_ctx->b = 2;
76635 nc_ctx->B = radix;
76636 nc_ctx->abs_pos = 0;
76637 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
76638 nc_ctx->is_fixed = 1;
76639 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
76640 /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
76641 * but add an extra digit for rounding.
76642 */
76643 nc_ctx->abs_pos = 1;
76644 nc_ctx->req_digits = (-digits + 1) - 1;
76645 } else {
76646 nc_ctx->req_digits = digits + 1;
76647 }
76648 } else {
76649 nc_ctx->is_fixed = 0;
76650 nc_ctx->req_digits = 0;
76651 }
76652
76653 if (c == DUK_FP_ZERO) {
76654 /* Zero special case: fake requested number of zero digits; ensure
76655 * no sign bit is printed. Relative and absolute fixed format
76656 * require separate handling.
76657 */
76658 duk_small_int_t count;
76659 if (nc_ctx->is_fixed) {
76660 if (nc_ctx->abs_pos) {
76661 count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
76662 } else {
76663 count = digits + 1; /* + 1 for rounding */
76664 }
76665 } else {
76666 count = 1;
76667 }
76668 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
76669 DUK_ASSERT(count >= 1);
76670 DUK_MEMZERO((void *) nc_ctx->digits, count);
76671 nc_ctx->count = count;
76672 nc_ctx->k = 1; /* 0.000... */
76673 neg = 0;
76674 goto zero_skip;
76675 }
76676
76677 duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
76678 DUK__BI_PRINT("f", &nc_ctx->f);
76679 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
76680
76681 /*
76682 * Dragon4 slow path digit generation.
76683 */
76684
76685 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
76686
76687 DUK_DDD(DUK_DDDPRINT("after prepare:"));
76688 DUK__BI_PRINT("r", &nc_ctx->r);
76689 DUK__BI_PRINT("s", &nc_ctx->s);
76690 DUK__BI_PRINT("mp", &nc_ctx->mp);
76691 DUK__BI_PRINT("mm", &nc_ctx->mm);
76692
76693 duk__dragon4_scale(nc_ctx);
76694
76695 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
76696 DUK__BI_PRINT("r", &nc_ctx->r);
76697 DUK__BI_PRINT("s", &nc_ctx->s);
76698 DUK__BI_PRINT("mp", &nc_ctx->mp);
76699 DUK__BI_PRINT("mm", &nc_ctx->mm);
76700
76701 duk__dragon4_generate(nc_ctx);
76702
76703 /*
76704 * Convert and push final string.
76705 */
76706
76707 zero_skip:
76708
76709 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
76710 /* Perform fixed-format rounding. */
76711 duk_small_int_t roundpos;
76712 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
76713 /* 'roundpos' is relative to nc_ctx->k and increases to the right
76714 * (opposite of how 'k' changes).
76715 */
76716 roundpos = -digits; /* absolute position for digit considered for rounding */
CURL_EXTERN CURLMcode curl_socket_t s
Definition multi.h:318

References duk__numconv_stringify_ctx::abs_pos, duk__numconv_stringify_ctx::b, duk__numconv_stringify_ctx::B, duk__numconv_stringify_ctx::count, duk__numconv_stringify_ctx::digits, DUK__BI_PRINT, duk__dragon4_convert_and_push(), duk__dragon4_double_to_ctx(), duk__dragon4_fixed_format_round(), duk__dragon4_format_uint32(), duk__dragon4_generate(), duk__dragon4_prepare(), duk__dragon4_scale(), DUK__NUMCONV_CTX_BIGINTS_SIZE, DUK_ASSERT, DUK_DDD, DUK_DDDPRINT, DUK_FP_INFINITE, DUK_FP_NAN, DUK_FP_ZERO, DUK_FPCLASSIFY, DUK_MEMZERO, DUK_N2S_FLAG_FIXED_FORMAT, DUK_N2S_FLAG_FRACTION_DIGITS, duk_pop(), duk_push_hstring_stridx(), duk_push_lstring(), duk_require_number(), DUK_SIGNBIT, DUK_STRIDX_INFINITY, DUK_STRIDX_MINUS_INFINITY, DUK_STRIDX_NAN, duk__numconv_stringify_ctx::e, duk__numconv_stringify_ctx::f, duk__numconv_stringify_ctx::is_fixed, duk__numconv_stringify_ctx::is_s2n, duk__numconv_stringify_ctx::k, duk__numconv_stringify_ctx::mm, duk__numconv_stringify_ctx::mp, duk__numconv_stringify_ctx::r, duk__numconv_stringify_ctx::req_digits, and duk__numconv_stringify_ctx::s.

Referenced by duk__enc_double(), duk_bi_number_prototype_to_exponential(), duk_bi_number_prototype_to_fixed(), duk_bi_number_prototype_to_precision(), duk_bi_number_prototype_to_string(), and duk_to_string().