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

Go to the source code of this file.

Macros

#define DUK_BI_DATE_ISO8601_BUFSIZE   48
 
#define DUK_BI_COMMONJS_MODULE_ID_LIMIT   256
 

Functions

DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts (duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags)
 
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts (duk_double_t *dparts, duk_small_uint_t flags)
 
DUK_INTERNAL_DECL void duk_bi_date_format_timeval (duk_double_t timeval, duk_uint8_t *out_buf)
 
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year (duk_int_t year)
 
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range (duk_double_t x)
 
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range (duk_double_t year)
 
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range (duk_double_t x)
 
DUK_INTERNAL_DECL void duk_bi_json_parse_helper (duk_context *ctx, duk_idx_t idx_value, duk_idx_t idx_reviver, duk_small_uint_t flags)
 
DUK_INTERNAL_DECL void duk_bi_json_stringify_helper (duk_context *ctx, duk_idx_t idx_value, duk_idx_t idx_replacer, duk_idx_t idx_space, duk_small_uint_t flags)
 

Macro Definition Documentation

◆ DUK_BI_COMMONJS_MODULE_ID_LIMIT

#define DUK_BI_COMMONJS_MODULE_ID_LIMIT   256

Definition at line 21 of file duktape-1.5.2/src-separate/duk_bi_protos.h.

◆ DUK_BI_DATE_ISO8601_BUFSIZE

#define DUK_BI_DATE_ISO8601_BUFSIZE   48

Definition at line 15 of file duktape-1.5.2/src-separate/duk_bi_protos.h.

Function Documentation

◆ duk_bi_date_format_timeval()

DUK_INTERNAL_DECL void duk_bi_date_format_timeval ( duk_double_t timeval,
duk_uint8_t * out_buf )

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

◆ duk_bi_date_get_timeval_from_dparts()

DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts ( duk_double_t * dparts,
duk_small_uint_t flags )

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

25098 {
25099 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
25100 dparts[i] = (duk_double_t) parts[i];
25101 }
25102 }
25103}
25104
25105/* Compute time value from (double) parts. The parts can be either UTC
25106 * or local time; if local, they need to be (conceptually) converted into
25107 * UTC time. The parts may represent valid or invalid time, and may be
25108 * wildly out of range (but may cancel each other and still come out in
25109 * the valid Date range).
25110 */
25112#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
25113 /* See comments below on MakeTime why these are volatile. */
25114 volatile duk_double_t tmp_time;
25115 volatile duk_double_t tmp_day;
25116 volatile duk_double_t d;
25117#else
25118 duk_double_t tmp_time;
25119 duk_double_t tmp_day;
25120 duk_double_t d;
25121#endif
25123 duk_int_t tzoff, tzoffprev1, tzoffprev2;
25124
25125 /* Expects 'this' at top of stack on entry. */
25126
25127 /* Coerce all finite parts with ToInteger(). ToInteger() must not
25128 * be called for NaN/Infinity because it will convert e.g. NaN to
25129 * zero. If ToInteger() has already been called, this has no side
25130 * effects and is idempotent.
25131 *
25132 * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
25133 * issues if the value is uninitialized.
25134 */
25135 for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
25136 /* SCANBUILD: scan-build complains here about assigned value
25137 * being garbage or undefined. This is correct but operating
25138 * on undefined values has no ill effect and is ignored by the
25139 * caller in the case where this happens.
25140 */
25141 d = dparts[i];
25142 if (DUK_ISFINITE(d)) {
25143 dparts[i] = duk_js_tointeger_number(d);
25144 }
25145 }
25146
25147 /* Use explicit steps in computation to try to ensure that
25148 * computation happens with intermediate results coerced to
25149 * double values (instead of using something more accurate).
25150 * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
25151 * rules (= Ecmascript '+' and '*' operators).
25152 *
25153 * Without 'volatile' even this approach fails on some platform
25154 * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
25155 * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
25156 * would fail because of some optimizations when computing tmp_time
25157 * (MakeTime below). Adding 'volatile' to tmp_time solved this
25158 * particular problem (annoyingly, also adding debug prints or
25159 * running the executable under valgrind hides it).
25160 */
25161
25162 /* MakeTime */
25163 tmp_time = 0.0;
25164 tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
25165 tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
25166 tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
25167 tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
25168
25169 /* MakeDay */
25170 tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
25171
25172 /* MakeDate */
25173 d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
25174
25175 DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
25176 (double) tmp_time, (double) tmp_day, (double) d));
25177
25178 /* Optional UTC conversion. */
25179 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25180 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
25181 * time value computed from UTC parts. At this point we only
25182 * have 'd' which is a time value computed from local parts, so
25183 * it is off by the UTC-to-local time offset which we don't know
25184 * yet. The current solution for computing the UTC-to-local
25185 * time offset is to iterate a few times and detect a fixed
25186 * point or a two-cycle loop (or a sanity iteration limit),
25187 * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
25188 *
25189 * E5.1 Section 15.9.1.9:
25190 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
25191 *
25192 * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
25193 */
25194
25195#if 0
25196 /* Old solution: don't iterate, incorrect */
25197 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
25198 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
25199 d -= tzoff * 1000L;
25200 DUK_UNREF(tzoffprev1);
25201 DUK_UNREF(tzoffprev2);
25202#endif
25203
25204 /* Iteration solution */
25205 tzoff = 0;
25206 tzoffprev1 = 999999999L; /* invalid value which never matches */
25207 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
25208 tzoffprev2 = tzoffprev1;
25209 tzoffprev1 = tzoff;
25210 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
25211 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
25212 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25213 if (tzoff == tzoffprev1) {
25214 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
25215 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25216 break;
25217 } else if (tzoff == tzoffprev2) {
25218 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
25219 * In these cases, favor a higher tzoffset to get a consistent
25220 * result which is independent of iteration count. Not sure if
25221 * this is a generically correct solution.
25222 */
unsigned int duk_small_uint_t
duk_int_fast32_t duk_int_t
#define DUK__LOCAL_TZOFFSET_MAXITER
DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags)
DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x)
#define DUK_DATE_FLAG_LOCALTIME
#define DUK_DATE_IDX_MILLISECOND
#define DUK_DATE_IDX_NUM_PARTS

◆ duk_bi_date_is_leap_year()

DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year ( duk_int_t year)

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

◆ duk_bi_date_timeval_in_leeway_range()

DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range ( duk_double_t x)

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

24801 {
24802 if ((year % 4) != 0) {
24803 return 0;

◆ duk_bi_date_timeval_in_valid_range()

DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range ( duk_double_t x)

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

◆ duk_bi_date_timeval_to_parts()

DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts ( duk_double_t d,
duk_int_t * parts,
duk_double_t * dparts,
duk_small_uint_t flags )

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

24951 {
24952 day_num += duk__days_in_month[i];
24953 if (i == 1 && is_leap) {
24954 day_num++;
24955 }
24956 }
24957
24958 /* If 'day' is NaN, returns NaN. */
24959 return (duk_double_t) day_num + day;
24960}
24961
24962/* Split time value into parts. The time value is assumed to be an internal
24963 * one, i.e. finite, no fractions. Possible local time adjustment has already
24964 * been applied when reading the time value.
24965 */
24967 duk_double_t d1, d2;
24968 duk_int_t t1, t2;
24969 duk_int_t day_since_epoch;
24970 duk_int_t year; /* does not fit into 16 bits */
24971 duk_small_int_t day_in_year;
24972 duk_small_int_t month;
24973 duk_small_int_t day;
24974 duk_small_int_t dim;
24975 duk_int_t jan1_since_epoch;
24976 duk_small_int_t jan1_weekday;
24977 duk_int_t equiv_year;
24979 duk_bool_t is_leap;
24980 duk_small_int_t arridx;
24981
24982 DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
24983 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
24984
24985 /* The timevalue must be in valid Ecmascript range, but since a local
24986 * time offset can be applied, we need to allow a +/- 24h leeway to
24987 * the value. In other words, although the UTC time is within the
24988 * Ecmascript range, the local part values can be just outside of it.
24989 */
24992
24993 /* these computations are guaranteed to be exact for the valid
24994 * E5 time value range, assuming milliseconds without fractions.
24995 */
24996 d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
24997 if (d1 < 0.0) {
24998 /* deal with negative values */
25000 }
25001 d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
25002 DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
25003 /* now expected to fit into a 32-bit integer */
25004 t1 = (duk_int_t) d1;
25005 t2 = (duk_int_t) d2;
25006 day_since_epoch = t2;
25007 DUK_ASSERT((duk_double_t) t1 == d1);
25008 DUK_ASSERT((duk_double_t) t2 == d2);
25009
25010 /* t1 = milliseconds within day (fits 32 bit)
25011 * t2 = day number from epoch (fits 32 bit, may be negative)
25012 */
25013
25014 parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
25015 parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
25016 parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
25017 parts[DUK_DATE_IDX_HOUR] = t1;
25018 DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
25019 DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
25020 DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
25021 DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
25022
25023 DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
25024 (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
25025 (long) parts[DUK_DATE_IDX_HOUR],
25026 (long) parts[DUK_DATE_IDX_MINUTE],
25027 (long) parts[DUK_DATE_IDX_SECOND],
25028 (long) parts[DUK_DATE_IDX_MILLISECOND]));
25029
25030 /* This assert depends on the input parts representing time inside
25031 * the Ecmascript range.
25032 */
25034 parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25035 DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
25036
25037 year = duk__year_from_day(t2, &day_in_year);
25038 day = day_in_year;
25039 is_leap = duk_bi_date_is_leap_year(year);
25040 for (month = 0; month < 12; month++) {
25041 dim = duk__days_in_month[month];
25042 if (month == 1 && is_leap) {
25043 dim++;
25044 }
25045 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
25046 (long) month, (long) dim, (long) day));
25047 if (day < dim) {
25048 break;
25049 }
25050 day -= dim;
25051 }
25052 DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
25053 DUK_ASSERT(month >= 0 && month <= 11);
25054 DUK_ASSERT(day >= 0 && day <= 31);
25055
25056 /* Equivalent year mapping, used to avoid DST trouble when platform
25057 * may fail to provide reasonable DST answers for dates outside the
25058 * ordinary range (e.g. 1970-2038). An equivalent year has the same
25059 * leap-year-ness as the original year and begins on the same weekday
25060 * (Jan 1).
25061 *
25062 * The year 2038 is avoided because there seem to be problems with it
25063 * on some platforms. The year 1970 is also avoided as there were
25064 * practical problems with it; an equivalent year is used for it too,
25065 * which breaks some DST computations for 1970 right now, see e.g.
25066 * test-bi-date-tzoffset-brute-fi.js.
25067 */
25068 if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
25069 DUK_ASSERT(is_leap == 0 || is_leap == 1);
25070
25071 jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
25072 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
25073 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25074 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
25075 arridx = jan1_weekday;
25076 if (is_leap) {
25077 arridx += 7;
25078 }
25079 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
25080
25081 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
25082 year = equiv_year;
25083 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
25084 "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
25085 (long) year, (long) day_in_year, (long) day_since_epoch,
25086 (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
duk_small_int_t duk_bool_t
DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year)
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year)
DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags)
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x)
DUK_LOCAL duk_uint8_t duk__date_equivyear[14]
DUK_LOCAL duk_uint8_t duk__days_in_month[12]
#define DUK_DATE_FLAG_EQUIVYEAR

◆ duk_bi_date_year_in_valid_range()

DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range ( duk_double_t year)

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

24805 {
24806 return 1;
24807 }

◆ duk_bi_json_parse_helper()

DUK_INTERNAL_DECL void duk_bi_json_parse_helper ( duk_context * ctx,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags )

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

31501 {
31502 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
31503 return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
31504 }
31505
31506 return 0;
31507}
31508#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
31509
31510/*
31511 * Top level wrappers
31512 */
31513
31516 duk_idx_t idx_value,
31517 duk_idx_t idx_reviver,
31518 duk_small_uint_t flags) {
31519 duk_hthread *thr = (duk_hthread *) ctx;
31520 duk_json_dec_ctx js_ctx_alloc;
31521 duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
31522 duk_hstring *h_text;
31523#ifdef DUK_USE_ASSERTIONS
31524 duk_idx_t entry_top = duk_get_top(ctx);
31525#endif
31526
31527 /* negative top-relative indices not allowed now */
31528 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31529 DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
31530
31531 DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
31532 (duk_tval *) duk_get_tval(ctx, idx_value),
31533 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31534 (unsigned long) flags,
31535 (long) duk_get_top(ctx)));
31536
31537 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31538 js_ctx->thr = thr;
31539#ifdef DUK_USE_EXPLICIT_NULL_INIT
31540 /* nothing now */
31541#endif
31543 DUK_ASSERT(js_ctx->recursion_depth == 0);
31544
31545 /* Flag handling currently assumes that flags are consistent. This is OK
31546 * because the call sites are now strictly controlled.
31547 */
31548
31549 js_ctx->flags = flags;
31550#if defined(DUK_USE_JX)
31551 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31552#endif
31553#if defined(DUK_USE_JC)
31555#endif
31556#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31558#endif
31559
31560 h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
31561 DUK_ASSERT(h_text != NULL);
31562
31563 /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
31564 * valid and points to the string NUL terminator (which is always
31565 * guaranteed for duk_hstrings.
31566 */
31567 js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
31568 js_ctx->p = js_ctx->p_start;
31569 js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
31571 DUK_ASSERT(*(js_ctx->p_end) == 0x00);
31572
31573 duk__dec_value(js_ctx); /* -> [ ... value ] */
31574
31575 /* Trailing whitespace has been eaten by duk__dec_value(), so if
31576 * we're not at end of input here, it's a SyntaxError.
31577 */
31578
31579 if (js_ctx->p != js_ctx->p_end) {
31580 duk__dec_syntax_error(js_ctx);
31581 }
31582
31583 if (duk_is_callable(ctx, idx_reviver)) {
31584 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
31585 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31586
31587 js_ctx->idx_reviver = idx_reviver;
31588
31589 duk_push_object(ctx);
31590 duk_dup(ctx, -2); /* -> [ ... val root val ] */
31591 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
31592 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
31593
31594 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
31595 (duk_tval *) duk_get_tval(ctx, -2),
31596 (duk_tval *) duk_get_tval(ctx, -1)));
31597
31598 duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
#define DUK_MEMZERO(p, n)
DUK_INTERNAL_DECL duk_hstring * duk_to_hstring(duk_context *ctx, duk_idx_t index)
#define DUK_HSTRING_GET_DATA(x)
DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx)
DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx)
DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx)
DUK_INTERNAL_DECL void duk_bi_json_parse_helper(duk_context *ctx, duk_idx_t idx_value, duk_idx_t idx_reviver, duk_small_uint_t flags)
#define DUK_HSTRING_GET_BYTELEN(x)
DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx)
#define DUK_STRIDX_EMPTY_STRING
DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index)
#define DUK_JSON_FLAG_EXT_CUSTOM
DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx)
#define DUK_JSON_FLAG_EXT_COMPATIBLE
DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx)
DUK_INTERNAL_DECL duk_tval * duk_get_tval(duk_context *ctx, duk_idx_t index)
#define duk_is_callable(ctx, index)
#define NULL
Definition gmacros.h:924

◆ duk_bi_json_stringify_helper()

DUK_INTERNAL_DECL void duk_bi_json_stringify_helper ( duk_context * ctx,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags )

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

31601 : %!T",
31602 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31603 }
31604
31605 /* Final result is at stack top. */
31606
31607 DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
31608 (duk_tval *) duk_get_tval(ctx, idx_value),
31609 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31610 (unsigned long) flags,
31611 (duk_tval *) duk_get_tval(ctx, -1),
31612 (long) duk_get_top(ctx)));
31613
31614 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
31615}
31616
31617DUK_INTERNAL
31618void duk_bi_json_stringify_helper(duk_context *ctx,
31619 duk_idx_t idx_value,
31620 duk_idx_t idx_replacer,
31621 duk_idx_t idx_space,
31622 duk_small_uint_t flags) {
31623 duk_hthread *thr = (duk_hthread *) ctx;
31624 duk_json_enc_ctx js_ctx_alloc;
31625 duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
31626 duk_hobject *h;
31627 duk_idx_t idx_holder;
31628 duk_idx_t entry_top;
31629
31630 /* negative top-relative indices not allowed now */
31631 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31632 DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
31633 DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
31634
31635 DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
31636 (duk_tval *) duk_get_tval(ctx, idx_value),
31637 (duk_tval *) duk_get_tval(ctx, idx_replacer),
31638 (duk_tval *) duk_get_tval(ctx, idx_space),
31639 (unsigned long) flags,
31640 (long) duk_get_top(ctx)));
31641
31642 entry_top = duk_get_top(ctx);
31643
31644 /*
31645 * Context init
31646 */
31647
31648 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31649 js_ctx->thr = thr;
31650#ifdef DUK_USE_EXPLICIT_NULL_INIT
31651 js_ctx->h_replacer = NULL;
31652 js_ctx->h_gap = NULL;
31653#endif
31654 js_ctx->idx_proplist = -1;
31655
31656 /* Flag handling currently assumes that flags are consistent. This is OK
31657 * because the call sites are now strictly controlled.
31658 */
31659
31660 js_ctx->flags = flags;
31661 js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
31662 js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
31663#ifdef DUK_USE_JX
31664 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31665#endif
31666#ifdef DUK_USE_JC
31667 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
31668#endif
31669#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31670 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
31671#endif
31672
31673 /* The #ifdef clutter here handles the JX/JC enable/disable
31674 * combinations properly.
31675 */
31676#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31677 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
31678#if defined(DUK_USE_JX)
31679 if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
31680 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
31681 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
31682 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
31683 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
31684 js_ctx->stridx_custom_function =
31685 (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
31686 DUK_STRIDX_JSON_EXT_FUNCTION2 :
31687 DUK_STRIDX_JSON_EXT_FUNCTION1;
31688 }
31689#endif /* DUK_USE_JX */
31690#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
31691 else
31692#endif /* DUK_USE_JX && DUK_USE_JC */
31693#if defined(DUK_USE_JC)
31694 if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
31695 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
31696 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
31697 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
31698 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
31699 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
31700 }
31701#endif /* DUK_USE_JC */
31702#endif /* DUK_USE_JX || DUK_USE_JC */
31703
31704#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31705 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
31706 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
31707 DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
31708 }
31709 else
31710#endif /* DUK_USE_JX || DUK_USE_JC */
31711 {
31712 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
31713 DUK_TYPE_MASK_POINTER |
31714 DUK_TYPE_MASK_BUFFER |
31715 DUK_TYPE_MASK_LIGHTFUNC;
31716 }
31717
31718 DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
31719
31720 js_ctx->idx_loop = duk_push_object_internal(ctx);
31721 DUK_ASSERT(js_ctx->idx_loop >= 0);
31722
31723 /* [ ... buf loop ] */
31724
31725 /*
31726 * Process replacer/proplist (2nd argument to JSON.stringify)
31727 */
31728
31729 h = duk_get_hobject(ctx, idx_replacer);
31730 if (h != NULL) {
31731 if (DUK_HOBJECT_IS_CALLABLE(h)) {
31732 js_ctx->h_replacer = h;
31733 } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
31734 /* Here the specification requires correct array index enumeration
31735 * which is a bit tricky for sparse arrays (it is handled by the
31736 * enum setup code). We now enumerate ancestors too, although the
31737 * specification is not very clear on whether that is required.
31738 */
31739
31740 duk_uarridx_t plist_idx = 0;
31741 duk_small_uint_t enum_flags;
31742
31743 js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
31744
31745 enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
31746 DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
31747 duk_enum(ctx, idx_replacer, enum_flags);
31748 while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
31749 /* [ ... proplist enum_obj key val ] */
31750 if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
31751 /* XXX: duplicates should be eliminated here */
31752 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
31753 (duk_tval *) duk_get_tval(ctx, -2),
31754 (duk_tval *) duk_get_tval(ctx, -1)));
31755 duk_to_string(ctx, -1); /* extra coercion of strings is OK */
31756 duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
31757 plist_idx++;
31758 duk_pop(ctx);
31759 } else {
31760 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
31761 (duk_tval *) duk_get_tval(ctx, -2),
31762 (duk_tval *) duk_get_tval(ctx, -1)));
31763 duk_pop_2(ctx);
31764 }
31765 }
31766 duk_pop(ctx); /* pop enum */
31767
31768 /* [ ... proplist ] */
31769 }
31770 }
31771
31772 /* [ ... buf loop (proplist) ] */
31773
31774 /*
31775 * Process space (3rd argument to JSON.stringify)
31776 */
31777
31778 h = duk_get_hobject(ctx, idx_space);
31779 if (h != NULL) {
31780 int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
31781 if (c == DUK_HOBJECT_CLASS_NUMBER) {
31782 duk_to_number(ctx, idx_space);
31783 } else if (c == DUK_HOBJECT_CLASS_STRING) {
31784 duk_to_string(ctx, idx_space);
31785 }
31786 }
31787
31788 if (duk_is_number(ctx, idx_space)) {
31789 duk_small_int_t nspace;
31790 /* spaces[] must be static to allow initializer with old compilers like BCC */
31791 static const char spaces[10] = {
31792 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
31793 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
31794 DUK_ASC_SPACE, DUK_ASC_SPACE
31795 }; /* XXX: helper */
31796
31797 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
31798 nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
31799 DUK_ASSERT(nspace >= 0 && nspace <= 10);
31800
31801 duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
31802 js_ctx->h_gap = duk_get_hstring(ctx, -1);
31803 DUK_ASSERT(js_ctx->h_gap != NULL);
31804 } else if (duk_is_string(ctx, idx_space)) {
31805 /* XXX: substring in-place at idx_place? */
31806 duk_dup(ctx, idx_space);
31807 duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
31808 js_ctx->h_gap = duk_get_hstring(ctx, -1);
31809 DUK_ASSERT(js_ctx->h_gap != NULL);
31810 } else {
31811 /* nop */
31812 }
31813
31814 if (js_ctx->h_gap != NULL) {
31815 /* if gap is empty, behave as if not given at all */
31816 if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
31817 js_ctx->h_gap = NULL;
31818 }
31819 }
31820
31821 /* [ ... buf loop (proplist) (gap) ] */
31822
31823 /*
31824 * Fast path: assume no mutation, iterate object property tables
31825 * directly; bail out if that assumption doesn't hold.
31826 */
31827
31828#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
31829 if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
31830 js_ctx->idx_proplist == -1) { /* proplist is very rare */
31831 duk_int_t pcall_rc;
31832#ifdef DUK_USE_MARK_AND_SWEEP
31833 duk_small_uint_t prev_mark_and_sweep_base_flags;
31834#endif
31835
31836 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
31837
31838 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
31839 * array so we don't need two counter checks in the fast path. The
31840 * slow path has a much larger recursion limit which we'll use if
31841 * necessary.
31842 */
31843 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
31844 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
31845 DUK_ASSERT(js_ctx->recursion_depth == 0);
31846
31847 /* Execute the fast path in a protected call. If any error is thrown,
31848 * fall back to the slow path. This includes e.g. recursion limit
31849 * because the fast path has a smaller recursion limit (and simpler,
31850 * limited loop detection).
31851 */
31852
31853 duk_push_pointer(ctx, (void *) js_ctx);
31854 duk_dup(ctx, idx_value);
31855
31856#if defined(DUK_USE_MARK_AND_SWEEP)
31857 /* Must prevent finalizers which may have arbitrary side effects. */
31858 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
31859 thr->heap->mark_and_sweep_base_flags |=
31860 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
31861 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
31862#endif
31863
31864 pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
31865
31866#if defined(DUK_USE_MARK_AND_SWEEP)
31867 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
31868#endif
31869 if (pcall_rc == DUK_EXEC_SUCCESS) {
31870 DUK_DD(DUK_DDPRINT("fast path successful"));
31871 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
31872 goto replace_finished;
31873 }
31874
31875 /* We come here for actual aborts (like encountering .toJSON())
31876 * but also for recursion/loop errors. Bufwriter size can be
31877 * kept because we'll probably need at least as much as we've
31878 * allocated so far.
31879 */
31880 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
31881 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
31882 js_ctx->recursion_depth = 0;
31883 }
31884#endif
31885
31886 /*
31887 * Create wrapper object and serialize
31888 */
31889
31890 idx_holder = duk_push_object(ctx);
31891 duk_dup(ctx, idx_value);
31892 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
31893
31894 DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
31895 "proplist=%!T, gap=%!O, holder=%!T",
31896 (unsigned long) js_ctx->flags,
31897 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
31898 (duk_heaphdr *) js_ctx->h_replacer,
31899 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
31900 (duk_heaphdr *) js_ctx->h_gap,
31901 (duk_tval *) duk_get_tval(ctx, -1)));
31902
31903 /* serialize the wrapper with empty string key */
31904
31905 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
31906
31907 /* [ ... buf loop (proplist) (gap) holder "" ] */
31908
31909 js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
31910 DUK_ASSERT(js_ctx->recursion_depth == 0);
31911
31912 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
31913 /* Result is undefined. */
31914 duk_push_undefined(ctx);
31915 } else {
31916 /* Convert buffer to result string. */
31917 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
31918 }
31919
31920 DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
31921 "proplist=%!T, gap=%!O, holder=%!T",
31922 (unsigned long) js_ctx->flags,
31923 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
31924 (duk_heaphdr *) js_ctx->h_replacer,
31925 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
31926 (duk_heaphdr *) js_ctx->h_gap,
31927 (duk_tval *) duk_get_tval(ctx, idx_holder)));
31928
31929 /* The stack has a variable shape here, so force it to the
31930 * desired one explicitly.
31931 */
31932
int value
Definition lsqlite3.c:2155