From 61504069051f4e5e7d15cbdb72a000cc551a8ec4 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sun, 1 Feb 2026 18:34:35 -0600 Subject: [PATCH] pretext --- archive/miniz.c | 2 +- fd.c | 8 +- fd_playdate.c | 8 +- net/enet.c | 6 +- net/http.c | 2 +- net/http_playdate.c | 2 +- net/socket.c | 12 +- playdate/json_playdate.c | 2 +- source/quickjs.c | 1411 +++++++++++++++++++------------------- source/quickjs.h | 6 +- 10 files changed, 731 insertions(+), 728 deletions(-) diff --git a/archive/miniz.c b/archive/miniz.c index 98163704..2851b01e 100644 --- a/archive/miniz.c +++ b/archive/miniz.c @@ -101,7 +101,7 @@ static JSValue js_miniz_compress(JSContext *js, JSValue this_val, size_t in_len = 0; const void *in_ptr = NULL; - if (JS_IsString(argv[0])) { + if (JS_IsText(argv[0])) { /* String → UTF-8 bytes without the terminating NUL */ cstring = JS_ToCStringLen(js, &in_len, argv[0]); if (!cstring) diff --git a/fd.c b/fd.c index 24a1aed6..832cdfb1 100644 --- a/fd.c +++ b/fd.c @@ -50,7 +50,7 @@ JSC_SCALL(fd_open, mode_t mode = 0644; // Parse optional flags argument - if (argc > 1 && JS_IsString(argv[1])) { + if (argc > 1 && JS_IsText(argv[1])) { const char *flag_str = JS_ToCString(js, argv[1]); flags = 0; @@ -78,7 +78,7 @@ JSC_CCALL(fd_write, size_t len; ssize_t wrote; - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *data = JS_ToCStringLen(js, &len, argv[1]); if (!data) return JS_EXCEPTION; wrote = write(fd, data, len); @@ -276,7 +276,7 @@ JSC_SCALL(fd_mkdir, JSC_SCALL(fd_mv, if (argc < 2) ret = JS_ThrowTypeError(js, "fd.mv requires 2 arguments: old path and new path"); - else if (!JS_IsString(argv[1])) + else if (!JS_IsText(argv[1])) ret = JS_ThrowTypeError(js, "second argument must be a string (new path)"); else { const char *new_path = JS_ToCString(js, argv[1]); @@ -289,7 +289,7 @@ JSC_SCALL(fd_mv, JSC_SCALL(fd_symlink, if (argc < 2) ret = JS_ThrowTypeError(js, "fd.symlink requires 2 arguments: target and link path"); - else if (!JS_IsString(argv[1])) + else if (!JS_IsText(argv[1])) ret = JS_ThrowTypeError(js, "second argument must be a string (link path)"); else { const char *link_path = JS_ToCString(js, argv[1]); diff --git a/fd_playdate.c b/fd_playdate.c index 897923f2..49d96cac 100644 --- a/fd_playdate.c +++ b/fd_playdate.c @@ -39,7 +39,7 @@ JSC_SCALL(fd_open, FileOptions flags = kFileRead; // Parse optional flags argument - if (argc > 1 && JS_IsString(argv[1])) { + if (argc > 1 && JS_IsText(argv[1])) { const char *flag_str = JS_ToCString(js, argv[1]); flags = 0; @@ -70,7 +70,7 @@ JSC_CCALL(fd_write, size_t len; int wrote; - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *data = JS_ToCStringLen(js, &len, argv[1]); if (!data) return JS_EXCEPTION; wrote = pd_file->write(fd, data, (unsigned int)len); @@ -202,7 +202,7 @@ JSC_SCALL(fd_mkdir, JSC_SCALL(fd_mv, if (argc < 2) ret = JS_ThrowTypeError(js, "fd.mv requires 2 arguments: old path and new path"); - else if (!JS_IsString(argv[1])) + else if (!JS_IsText(argv[1])) ret = JS_ThrowTypeError(js, "second argument must be a string (new path)"); else { const char *new_path = JS_ToCString(js, argv[1]); @@ -216,7 +216,7 @@ JSC_SCALL(fd_mv, JSC_SCALL(fd_symlink, // Not supported - if (argc >= 2 && JS_IsString(argv[1])) { + if (argc >= 2 && JS_IsText(argv[1])) { // consume arg JS_FreeCString(js, JS_ToCString(js, argv[1])); } diff --git a/net/enet.c b/net/enet.c index c5a36c2f..d64d7bbc 100644 --- a/net/enet.c +++ b/net/enet.c @@ -70,7 +70,7 @@ static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int ar JSValue config_obj = argv[0]; JSValue addr_val = JS_GetPropertyStr(ctx, config_obj, "address"); - const char *addr_str = JS_IsString(addr_val) ? JS_ToCString(ctx, addr_val) : NULL; + const char *addr_str = JS_IsText(addr_val) ? JS_ToCString(ctx, addr_val) : NULL; JS_FreeValue(ctx, addr_val); if (!addr_str) @@ -245,7 +245,7 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int size_t data_len = 0; uint8_t *buf = NULL; - if (JS_IsString(argv[0])) { + if (JS_IsText(argv[0])) { data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); if (!data_str) return JS_EXCEPTION; } else if (js_is_blob(ctx,argv[0])) { @@ -310,7 +310,7 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc size_t data_len = 0; uint8_t *buf = NULL; - if (JS_IsString(argv[0])) { + if (JS_IsText(argv[0])) { data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); if (!data_str) return JS_EXCEPTION; } else if (js_is_blob(ctx,argv[0])) { diff --git a/net/http.c b/net/http.c index cfa1a4c3..fb3b8cd4 100644 --- a/net/http.c +++ b/net/http.c @@ -293,7 +293,7 @@ static int par_easycurl_to_memory(char const *url, par_byte **data, int *nbytes) // Performs a blocking HTTP GET and returns a QuickJS Blob of the body static JSValue js_fetch_picoparser(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc < 1 || !JS_IsString(argv[0])) + if (argc < 1 || !JS_IsText(argv[0])) return JS_ThrowTypeError(ctx, "fetch: URL string required"); const char *url = JS_ToCString(ctx, argv[0]); diff --git a/net/http_playdate.c b/net/http_playdate.c index 869858d0..f8881a57 100644 --- a/net/http_playdate.c +++ b/net/http_playdate.c @@ -135,7 +135,7 @@ static int parse_url(const char *url, char **host, int *port, char **path, int * // Performs a blocking HTTP GET and returns a QuickJS Blob of the body static JSValue js_fetch_playdate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - if (argc < 1 || !JS_IsString(argv[0])) + if (argc < 1 || !JS_IsText(argv[0])) return JS_ThrowTypeError(ctx, "fetch: URL string required"); if (!pd_network || !pd_network->http) { diff --git a/net/socket.c b/net/socket.c index ea168f52..a0c56d2e 100644 --- a/net/socket.c +++ b/net/socket.c @@ -144,7 +144,7 @@ JSC_CCALL(socket_socket, int protocol = 0; // Parse domain - if (JS_IsString(argv[0])) { + if (JS_IsText(argv[0])) { const char *domain_str = JS_ToCString(js, argv[0]); if (strcmp(domain_str, "AF_INET") == 0) domain = AF_INET; else if (strcmp(domain_str, "AF_INET6") == 0) domain = AF_INET6; @@ -156,7 +156,7 @@ JSC_CCALL(socket_socket, // Parse type if (argc > 1) { - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *type_str = JS_ToCString(js, argv[1]); if (strcmp(type_str, "SOCK_STREAM") == 0) type = SOCK_STREAM; else if (strcmp(type_str, "SOCK_DGRAM") == 0) type = SOCK_DGRAM; @@ -297,7 +297,7 @@ JSC_CCALL(socket_send, flags = js2number(js, argv[2]); } - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *data = JS_ToCStringLen(js, &len, argv[1]); sent = send(sockfd, data, len, flags); JS_FreeCString(js, data); @@ -385,7 +385,7 @@ JSC_CCALL(socket_sendto, to_len = sizeof(addr); } - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *data = JS_ToCStringLen(js, &len, argv[1]); sent = sendto(sockfd, data, len, flags, to_addr, to_len); JS_FreeCString(js, data); @@ -525,7 +525,7 @@ JSC_CCALL(socket_setsockopt, int optname = 0; // Parse level - if (JS_IsString(argv[1])) { + if (JS_IsText(argv[1])) { const char *level_str = JS_ToCString(js, argv[1]); if (strcmp(level_str, "SOL_SOCKET") == 0) level = SOL_SOCKET; else if (strcmp(level_str, "IPPROTO_TCP") == 0) level = IPPROTO_TCP; @@ -537,7 +537,7 @@ JSC_CCALL(socket_setsockopt, } // Parse option name - if (JS_IsString(argv[2])) { + if (JS_IsText(argv[2])) { const char *opt_str = JS_ToCString(js, argv[2]); if (strcmp(opt_str, "SO_REUSEADDR") == 0) optname = SO_REUSEADDR; else if (strcmp(opt_str, "SO_KEEPALIVE") == 0) optname = SO_KEEPALIVE; diff --git a/playdate/json_playdate.c b/playdate/json_playdate.c index 40b26c53..8ddf2e81 100644 --- a/playdate/json_playdate.c +++ b/playdate/json_playdate.c @@ -145,7 +145,7 @@ static void encode_js_value(json_encoder *enc, JSContext *js, JSValue val) { double d = js2number(js, val); if (d == (int)d) enc->writeInt(enc, (int)d); else enc->writeDouble(enc, d); - } else if (JS_IsString(val)) { + } else if (JS_IsText(val)) { size_t len; const char *str = JS_ToCStringLen(js, &len, val); enc->writeString(enc, str, len); diff --git a/source/quickjs.c b/source/quickjs.c index 017dc834..1986f1f3 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -2336,7 +2336,7 @@ int JS_GetStripInfo (JSRuntime *rt) { return rt->strip_flags; } /* Allocate a string using bump allocation from context heap. Note: the string contents are uninitialized */ -static JSText *js_alloc_string (JSContext *ctx, int max_len) { +static JSText *js_alloc_string(JSContext *ctx, int max_len) { JSText *str; /* Allocate packed UTF-32: 2 chars per 64-bit word. */ size_t data_words = (max_len + 1) / 2; @@ -2347,9 +2347,9 @@ static JSText *js_alloc_string (JSContext *ctx, int max_len) { JS_ThrowOutOfMemory(ctx); return NULL; } - /* Initialize objhdr_t with OBJ_TEXT type so JS_IsText can detect it */ + /* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */ str->hdr = objhdr_make(max_len, OBJ_TEXT, false, false, false, false); - str->len = max_len; + str->length = 0; /* length starts at 0, capacity is in hdr */ return str; } @@ -2617,12 +2617,12 @@ static JSText *js_alloc_string (JSContext *ctx, int max_len); static inline int is_num (int c) { return c >= '0' && c <= '9'; } /* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */ -static inline BOOL is_num_string (uint32_t *pval, const JSText *p) { +static inline BOOL is_num_string(uint32_t *pval, const JSText *p) { uint32_t n; uint64_t n64; int c, i, len; - len = p->len; + len = (int)JSText_len(p); if (len == 0 || len > 10) return FALSE; c = string_get (p, 0); if (is_num (c)) { @@ -2660,20 +2660,18 @@ static __maybe_unused void JS_DumpChar (FILE *fo, int c, int sep) { } } -static __maybe_unused void JS_DumpString (JSRuntime *rt, const JSText *p) { - int i, sep; +static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSText *p) { + int i; if (p == NULL) { printf (""); return; } - printf ("%d", p->header.ref_count); - sep = (p->header.ref_count == 1) ? '\"' : '\''; - putchar (sep); - for (i = 0; i < p->len; i++) { - JS_DumpChar (stdout, string_get (p, i), sep); + putchar ('"'); + for (i = 0; i < (int)JSText_len(p); i++) { + JS_DumpChar (stdout, string_get (p, i), '"'); } - putchar (sep); + putchar ('"'); } static inline BOOL JS_IsEmptyString (JSValue v) { @@ -2796,7 +2794,7 @@ static JSValue js_new_string16_len (JSContext *ctx, const uint16_t *buf, int len static JSValue js_sub_string (JSContext *ctx, JSText *p, int start, int end) { int i; int len = end - start; - if (start == 0 && end == p->len) { + if (start == 0 && end == (int)JSText_len(p)) { return JS_DupValue (ctx, JS_MKPTR(p)); } JSText *str = js_alloc_string (ctx, len); @@ -2806,88 +2804,109 @@ static JSValue js_sub_string (JSContext *ctx, JSText *p, int start, int end) { return JS_MKPTR(str); } -static no_inline JSText *pretext_realloc (JSText *s, int new_len, int c) { - JSText *new_str; - int new_size; - size_t new_size_bytes, slack; - - if (s->error_status) return -1; - - if (new_len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError (s->ctx, "string too long"); - return string_buffer_set_error (s); - } - new_size = min_int (max_int (new_len, s->size * 3 / 2), JS_STRING_LEN_MAX); - - /* JSText stores UTF-32 packed into uint64_t (2 chars per word). */ - new_size_bytes - = sizeof (JSText) + ((new_size + 1) / 2) * sizeof (uint64_t); - new_str = js_realloc2 (s->ctx, s->str, new_size_bytes, &slack); - if (!new_str) return string_buffer_set_error (s); - new_size - = min_int (new_size + (slack / sizeof (uint64_t)) * 2, JS_STRING_LEN_MAX); - s->size = new_size; - s->str = new_str; - return 0; +/* Allocate a new pretext (mutable JSText) with initial capacity */ +static JSText *pretext_init(JSContext *ctx, int capacity) { + if (capacity <= 0) capacity = 16; + JSText *s = js_alloc_string(ctx, capacity); + if (!s) return NULL; + s->length = 0; + return s; } -static no_inline int string_buffer_putc_slow (StringBuffer *s, uint32_t c) { - if (unlikely (s->len >= s->size)) { - if (string_buffer_realloc (s, s->len + 1, c)) return -1; +/* Free a pretext on error paths */ +static void pretext_free(JSContext *ctx, JSText *s) { + if (s) js_free(ctx, s); +} + +/* Reallocate a pretext to hold new_len characters */ +static no_inline JSText *pretext_realloc(JSContext *ctx, JSText *s, int new_len) { + if (new_len > JS_STRING_LEN_MAX) { + JS_ThrowInternalError(ctx, "string too long"); + return NULL; } - string_put (s->str, s->len++, c); - return 0; + int old_cap = (int)objhdr_cap56(s->hdr); + int new_cap = min_int(max_int(new_len, old_cap * 3 / 2), JS_STRING_LEN_MAX); + + /* JSText stores UTF-32 packed into uint64_t (2 chars per word). */ + size_t new_size_bytes = sizeof(JSText) + ((new_cap + 1) / 2) * sizeof(uint64_t); + size_t slack; + JSText *new_str = js_realloc2(ctx, s, new_size_bytes, &slack); + if (!new_str) return NULL; + new_cap = min_int(new_cap + (int)(slack / sizeof(uint64_t)) * 2, JS_STRING_LEN_MAX); + objhdr_set_cap56(&new_str->hdr, new_cap); + return new_str; +} + +static no_inline JSText *pretext_putc_slow(JSContext *ctx, JSText *s, uint32_t c) { + int len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (unlikely(len >= cap)) { + s = pretext_realloc(ctx, s, len + 1); + if (!s) return NULL; + } + string_put(s, len, c); + s->length++; + return s; } /* 0 <= c <= 0xff */ -static int string_buffer_putc8 (StringBuffer *s, uint32_t c) { - if (unlikely (s->len >= s->size)) { - if (string_buffer_realloc (s, s->len + 1, c)) return -1; +static JSText *pretext_putc8(JSContext *ctx, JSText *s, uint32_t c) { + int len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (unlikely(len >= cap)) { + s = pretext_realloc(ctx, s, len + 1); + if (!s) return NULL; } - string_put (s->str, s->len++, c); - return 0; + string_put(s, len, c); + s->length++; + return s; } /* 0 <= c <= 0xffff */ -static int string_buffer_putc16 (StringBuffer *s, uint32_t c) { - if (likely (s->len < s->size)) { - string_put (s->str, s->len++, c); - return 0; +static JSText *pretext_putc16(JSContext *ctx, JSText *s, uint32_t c) { + int len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (likely(len < cap)) { + string_put(s, len, c); + s->length++; + return s; } - return string_buffer_putc_slow (s, c); + return pretext_putc_slow(ctx, s, c); } /* 0 <= c <= 0x10ffff */ -static int string_buffer_putc (StringBuffer *s, uint32_t c) { - if (unlikely (c >= 0x10000)) { +static JSText *pretext_putc(JSContext *ctx, JSText *s, uint32_t c) { + if (unlikely(c >= 0x10000)) { /* surrogate pair */ - if (string_buffer_putc16 (s, get_hi_surrogate (c))) return -1; - c = get_lo_surrogate (c); + s = pretext_putc16(ctx, s, get_hi_surrogate(c)); + if (!s) return NULL; + c = get_lo_surrogate(c); } - return string_buffer_putc16 (s, c); + return pretext_putc16(ctx, s, c); } -static int string_buffer_write32 (StringBuffer *s, const uint32_t *p, - int len) { - int i; - if (s->len + len > s->size) { - if (string_buffer_realloc (s, s->len + len, 0)) return -1; +static JSText *pretext_write32(JSContext *ctx, JSText *s, const uint32_t *p, int len) { + int cur_len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (cur_len + len > cap) { + s = pretext_realloc(ctx, s, cur_len + len); + if (!s) return NULL; } - for (i = 0; i < len; i++) { - string_put (s->str, s->len + i, p[i]); + for (int i = 0; i < len; i++) { + string_put(s, cur_len + i, p[i]); } - s->len += len; - return 0; + s->length += len; + return s; } -static int string_getc (const JSText *p, int *pidx) { +static int string_getc(const JSText *p, int *pidx) { int idx, c, c1; idx = *pidx; - c = string_get (p, idx++); - if (is_hi_surrogate (c) && idx < p->len) { - c1 = string_get (p, idx); - if (is_lo_surrogate (c1)) { - c = from_surrogate (c, c1); + c = string_get(p, idx++); + if (is_hi_surrogate(c) && idx < (int)JSText_len(p)) { + c1 = string_get(p, idx); + if (is_lo_surrogate(c1)) { + c = from_surrogate(c, c1); idx++; } } @@ -2895,202 +2914,123 @@ static int string_getc (const JSText *p, int *pidx) { return c; } -static JSText *pretext_write8 (JSText *s, const uint8_t *p, int len) { - int i; - - if (s->len + len > s->size) { - if (string_buffer_realloc (s, s->len + len, 0)) return -1; +static JSText *pretext_write8(JSContext *ctx, JSText *s, const uint8_t *p, int len) { + int cur_len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (cur_len + len > cap) { + s = pretext_realloc(ctx, s, cur_len + len); + if (!s) return NULL; } - for (i = 0; i < len; i++) { - string_put (s->str, s->len + i, p[i]); + for (int i = 0; i < len; i++) { + string_put(s, cur_len + i, p[i]); } - s->len += len; - return 0; + s->length += len; + return s; } -static int string_buffer_write16 (StringBuffer *s, const uint16_t *p, - int len) { - int i; - - if (s->len + len > s->size) { - if (string_buffer_realloc (s, s->len + len, 0)) return -1; +static JSText *pretext_write16(JSContext *ctx, JSText *s, const uint16_t *p, int len) { + int cur_len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (cur_len + len > cap) { + s = pretext_realloc(ctx, s, cur_len + len); + if (!s) return NULL; } - for (i = 0; i < len; i++) { - string_put (s->str, s->len + i, p[i]); + for (int i = 0; i < len; i++) { + string_put(s, cur_len + i, p[i]); } - s->len += len; - return 0; + s->length += len; + return s; } /* appending an ASCII string */ -static int string_buffer_puts8 (StringBuffer *s, const char *str) { - return string_buffer_write8 (s, (const uint8_t *)str, strlen (str)); +static JSText *pretext_puts8(JSContext *ctx, JSText *s, const char *str) { + return pretext_write8(ctx, s, (const uint8_t *)str, strlen(str)); } -static int string_buffer_concat (StringBuffer *s, const JSText *p, - uint32_t from, uint32_t to) { - if (to <= from) return 0; +static JSText *pretext_concat(JSContext *ctx, JSText *s, const JSText *p, + uint32_t from, uint32_t to) { + if (to <= from) return s; int len = (int)(to - from); - if (s->len + len > s->size) { - if (string_buffer_realloc (s, s->len + len, 0)) return -1; + int cur_len = (int)s->length; + int cap = (int)objhdr_cap56(s->hdr); + if (cur_len + len > cap) { + s = pretext_realloc(ctx, s, cur_len + len); + if (!s) return NULL; } for (int i = 0; i < len; i++) { - string_put (s->str, s->len + i, string_get (p, (int)from + i)); + string_put(s, cur_len + i, string_get(p, (int)from + i)); } - s->len += len; - return 0; + s->length += len; + return s; } -static JSText *string_buffer_concat_value (JSText *s, JSValue v) { - if (MIST_IsImmediateASCII (v)) { - int len = MIST_GetImmediateASCIILen (v); - char buf[8]; - for (int i = 0; i < len; i++) - buf[i] = MIST_GetImmediateASCIIChar (v, i); - return string_buffer_write8 (s, (const uint8_t *)buf, len); - } - if (JS_IsText (v)) { - JSText *p = JS_VALUE_GET_PTR (v); - return string_buffer_concat (s, p, 0, p->length); - } - JSValue v1 = JS_ToString (s->ctx, v); - if (JS_IsException (v1)) return string_buffer_set_error (s); - - if (MIST_IsImmediateASCII (v1)) { - int len = MIST_GetImmediateASCIILen (v1); - char buf[8]; - for (int i = 0; i < len; i++) - buf[i] = MIST_GetImmediateASCIIChar (v1, i); - int res = string_buffer_write8 (s, (const uint8_t *)buf, len); - JS_FreeValue (s->ctx, v1); - return res; - } - - JSText *p = JS_VALUE_GET_STRING (v1); - int res = string_buffer_concat (s, p, 0, p->len); - JS_FreeValue (s->ctx, v1); - return res; -} - -static inline void mist_string_put(JSText *text, uint32_t utf32) -{ - int word_idx = text->len / 2; - int shift = (1 - (text->len % 2)) * 32; - word_t mask = (word_t)0xFFFFFFFF << shift; - text->packed[word_idx] = (text->packed[word_idx] & ~mask) | ((word_t)utf32 << shift); - text->length++; -} - -static JSText *text_puts(JSContext *ctx, JSText *text, const char *str) -{ - if (objhdr_s(text->hdr)) return NULL; - int len = strlen(str); - if (text->len + len > objhdr_cap56(text->hdr)) { - text = js_alloc_string(ctx, (text->len + len) * 2); - if (!text) return NULL; - } - for (int i = 0; i < len; i++) - mist_string_put(text, str[i]); - return text; -} - -static JSText *text_putc(JSContext *ctx, JSText *text, uint32_t c) -{ - if (objhdr_s(text->hdr)) return NULL; - if (text->len + 1 > objhdr_cap56(text->hdr)) { - text = js_alloc_string(ctx, (text->len + 1) * 2); - if (!text) return NULL; - } - mist_string_put(text, c); - return text; -} - -static JSText *text_concat(JSContext *ctx, JSText *text, JSValue v) -{ - if (objhdr_s(text->hdr)) return NULL; - +static JSText *pretext_concat_value(JSContext *ctx, JSText *s, JSValue v) { if (MIST_IsImmediateASCII(v)) { int len = MIST_GetImmediateASCIILen(v); - word_t text_len = JSText_len(text); - if (text_len + len > objhdr_cap56(text->hdr)) { - text = js_alloc_string(ctx, (text_len + len) * 2); - if (!text) return NULL; - } + char buf[8]; for (int i = 0; i < len; i++) - mist_string_put(text, MIST_GetImmediateASCIIChar(v, i)); - - return text; + buf[i] = MIST_GetImmediateASCIIChar(v, i); + return pretext_write8(ctx, s, (const uint8_t *)buf, len); } - if (JS_IsText(v)) { - JSText *src = (JSText *)JS_VALUE_GET_PTR(v); - word_t src_len = JSText_len(src); - word_t text_len = JSText_len(text); - if (text_len + src_len > objhdr_cap56(text->hdr)) { - text = js_alloc_string(ctx, (text_len + src_len) * 2); - if (!text) return NULL; - } - for (int i = 0; i < src_len; i++) - mist_string_put(text, JSText_get(src, i)); - return text; + JSText *p = JS_VALUE_GET_PTR(v); + return pretext_concat(ctx, s, p, 0, (uint32_t)JSText_len(p)); } - - return NULL; + JSValue v1 = JS_ToString(ctx, v); + if (JS_IsException(v1)) return NULL; + + if (MIST_IsImmediateASCII(v1)) { + int len = MIST_GetImmediateASCIILen(v1); + char buf[8]; + for (int i = 0; i < len; i++) + buf[i] = MIST_GetImmediateASCIIChar(v1, i); + s = pretext_write8(ctx, s, (const uint8_t *)buf, len); + JS_FreeValue(ctx, v1); + return s; + } + + JSText *p = JS_VALUE_GET_STRING(v1); + s = pretext_concat(ctx, s, p, 0, (uint32_t)JSText_len(p)); + JS_FreeValue(ctx, v1); + return s; } -static int string_buffer_concat_value_free (StringBuffer *s, JSValue v) { +static JSText *pretext_concat_value_free(JSContext *ctx, JSText *s, JSValue v) { JSText *p; - int res; - if (s->error_status) { - /* prevent exception overload */ - JS_FreeValue (s->ctx, v); - return -1; + if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { + v = JS_ToStringFree(ctx, v); + if (JS_IsException(v)) return NULL; } - if (unlikely (JS_VALUE_GET_TAG (v) != JS_TAG_STRING)) { - v = JS_ToStringFree (s->ctx, v); - if (JS_IsException (v)) return string_buffer_set_error (s); - } - p = JS_VALUE_GET_STRING (v); - res = string_buffer_concat (s, p, 0, p->len); - JS_FreeValue (s->ctx, v); - return res; + p = JS_VALUE_GET_STRING(v); + s = pretext_concat(ctx, s, p, 0, (uint32_t)JSText_len(p)); + JS_FreeValue(ctx, v); + return s; } -static JSValue text_concat_end(JSText *text) { - if (objhdr_s(text->hdr)) return JS_EXCEPTION; - objhdr_set_cap56(&text->hdr, text->len); - text->length = 0; - obj_set_stone(&text->hdr); - return JS_MKPTR(text); -} - -static JSValue string_buffer_end (StringBuffer *s) { - JSText *str; - str = s->str; - if (s->error_status) return JS_EXCEPTION; - if (s->len == 0) { - js_free (s->ctx, str); - s->str = NULL; +/* Finalize a pretext into an immutable JSValue string */ +static JSValue pretext_end(JSContext *ctx, JSText *s) { + if (!s) return JS_EXCEPTION; + int len = (int)s->length; + if (len == 0) { + js_free(ctx, s); return JS_KEY_empty; } - if (s->len < s->size) { - /* smaller size so js_realloc should not fail, but OK if it does */ - /* XXX: should add some slack to avoid unnecessary calls */ - /* XXX: might need to use malloc+free to ensure smaller size */ - str = js_realloc_rt (s->ctx->rt, str, - sizeof (JSText) + (s->len + 1) * sizeof (uint32_t)); - if (str == NULL) str = s->str; - s->str = str; + int cap = (int)objhdr_cap56(s->hdr); + if (len < cap) { + /* Try to shrink, but OK if realloc fails */ + size_t new_size = sizeof(JSText) + ((len + 1) / 2) * sizeof(uint64_t); + JSText *new_str = js_realloc_rt(ctx->rt, s, new_size); + if (new_str) s = new_str; } - /* explicit null term if needed or just leave it */ #ifdef DUMP_LEAKS - list_add_tail (&str->link, &s->ctx->rt->string_list); + list_add_tail(&s->link, &ctx->rt->string_list); #endif - /* str->is_wide_char = s->is_wide_char; removed */ - str->len = s->len; - s->str = NULL; - return JS_MKPTR(str); + /* Set final length in capacity field and clear length for hash storage */ + objhdr_set_cap56(&s->hdr, len); + s->length = 0; + obj_set_stone(&s->hdr); + return JS_MKPTR(s); } /* Count leading ASCII characters in buffer */ @@ -3102,46 +3042,52 @@ static size_t count_ascii (const uint8_t *buf, size_t len) { } /* create a string from a UTF-8 buffer */ -JSValue JS_NewStringLen (JSContext *ctx, const char *buf, size_t buf_len) { +JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) { if (buf_len > JS_STRING_LEN_MAX) - return JS_ThrowInternalError (ctx, "string too long"); + return JS_ThrowInternalError(ctx, "string too long"); - if (len <= MIST_ASCII_MAX_LEN) { + if (buf_len <= MIST_ASCII_MAX_LEN) { JSValue ret = MIST_TryNewImmediateASCII(buf, buf_len); if (!JS_IsNull(ret)) return ret; } - JSValue ret = js_new_string8_len(ctx, buf, buf_len); - if (!JS_IsNull(ret)) return text_concat_end(ret); - - return JS_EXCEPTION; + JSText *str = js_alloc_string(ctx, (int)buf_len); + if (!str) return JS_ThrowMemoryError(ctx); + for (size_t i = 0; i < buf_len; i++) + string_put(str, (int)i, (unsigned char)buf[i]); + str->length = buf_len; + return pretext_end(ctx, str); } -static JSValue JS_ConcatString3 (JSContext *ctx, const char *str1, - JSValue str2, const char *str3) { - StringBuffer b_s, *b = &b_s; +static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, + JSValue str2, const char *str3) { + JSText *b; int len1, len3; JSText *p; - if (unlikely (JS_VALUE_GET_TAG (str2) != JS_TAG_STRING)) { - str2 = JS_ToStringFree (ctx, str2); - if (JS_IsException (str2)) goto fail; + if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) { + str2 = JS_ToStringFree(ctx, str2); + if (JS_IsException(str2)) goto fail; } - p = JS_VALUE_GET_STRING (str2); - len1 = strlen (str1); - len3 = strlen (str3); + p = JS_VALUE_GET_STRING(str2); + len1 = strlen(str1); + len3 = strlen(str3); - if (string_buffer_init (ctx, b, len1 + p->len + len3)) goto fail; + b = pretext_init(ctx, len1 + (int)JSText_len(p) + len3); + if (!b) goto fail; - string_buffer_write8 (b, (const uint8_t *)str1, len1); - string_buffer_concat (b, p, 0, p->len); - string_buffer_write8 (b, (const uint8_t *)str3, len3); + b = pretext_write8(ctx, b, (const uint8_t *)str1, len1); + if (!b) goto fail; + b = pretext_concat(ctx, b, p, 0, (uint32_t)JSText_len(p)); + if (!b) goto fail; + b = pretext_write8(ctx, b, (const uint8_t *)str3, len3); + if (!b) goto fail; - JS_FreeValue (ctx, str2); - return string_buffer_end (b); + JS_FreeValue(ctx, str2); + return pretext_end(ctx, b); fail: - JS_FreeValue (ctx, str2); + JS_FreeValue(ctx, str2); return JS_EXCEPTION; } @@ -3164,8 +3110,8 @@ const char *JS_ToCStringLen2 (JSContext *ctx, size_t *plen, JSValue val1, val = JS_DupValue (ctx, val1); } - str = JS_VALUE_GET_STRING (val); - len = str->len; + str = JS_VALUE_GET_STRING(val); + len = (int)JSText_len(str); /* Calculate UTF-8 size */ size = 0; @@ -3210,22 +3156,26 @@ void JS_FreeCString (JSContext *ctx, const char *ptr) { static int js_string_compare (JSContext *ctx, const JSText *p1, const JSText *p2) { int res, len, i; - len = min_int (p1->len, p2->len); + int len1 = (int)JSText_len(p1); + int len2 = (int)JSText_len(p2); + len = min_int (len1, len2); for (i = 0; i < len; i++) { uint32_t c1 = string_get (p1, i); uint32_t c2 = string_get (p2, i); if (c1 != c2) return c1 < c2 ? -1 : 1; } - if (p1->len == p2->len) return 0; - return p1->len < p2->len ? -1 : 1; + if (len1 == len2) return 0; + return len1 < len2 ? -1 : 1; } static JSValue JS_ConcatString1 (JSContext *ctx, const JSText *p1, const JSText *p2) { JSText *p; uint32_t len; + int len1 = (int)JSText_len(p1); + int len2 = (int)JSText_len(p2); - len = p1->len + p2->len; + len = len1 + len2; if (len > JS_STRING_LEN_MAX) return JS_ThrowInternalError (ctx, "string too long"); p = js_alloc_string (ctx, len); @@ -3233,10 +3183,10 @@ static JSValue JS_ConcatString1 (JSContext *ctx, const JSText *p1, /* Pack first string */ { int i; - for (i = 0; i < p1->len; i++) + for (i = 0; i < len1; i++) string_put (p, i, string_get (p1, i)); - for (i = 0; i < p2->len; i++) - string_put (p, p1->len + i, string_get (p2, i)); + for (i = 0; i < len2; i++) + string_put (p, len1 + i, string_get (p2, i)); } return JS_MKPTR(p); } @@ -3248,21 +3198,22 @@ static BOOL JS_ConcatStringInPlace (JSContext *ctx, JSText *p1, size_t size1; int64_t new_len; size_t words_needed; + int64_t len1 = JSText_len(p1); + int64_t len2 = JSText_len(p2); - if (p2->len == 0) return TRUE; - if (p1->header.ref_count != 1) return FALSE; + if (len2 == 0) return TRUE; - new_len = p1->len + p2->len; + new_len = len1 + len2; /* UTF-32: 2 chars per 64-bit word, round up */ words_needed = (new_len + 1) / 2; size1 = js_malloc_usable_size (ctx, p1); if (size1 >= sizeof (*p1) + words_needed * sizeof (uint64_t)) { /* Append p2's characters using string_put/string_get */ - for (int64_t i = 0; i < p2->len; i++) { - string_put (p1, p1->len + i, string_get (p2, i)); + for (int64_t i = 0; i < len2; i++) { + string_put (p1, len1 + i, string_get (p2, i)); } - p1->len = new_len; + objhdr_set_cap56(&p1->hdr, new_len); return TRUE; } } @@ -3804,13 +3755,12 @@ typedef struct JSMemoryUsage_helper { static void compute_value_size (JSValue val, JSMemoryUsage_helper *hp); -static void compute_JSText_size (JSText *str, JSMemoryUsage_helper *hp) { +static void compute_JSText_size(JSText *str, JSMemoryUsage_helper *hp) { /* UTF-32 packs 2 chars per 64-bit word */ - double s_ref_count = str->header.ref_count; - size_t data_words = (str->len + 1) / 2; - hp->str_count += 1 / s_ref_count; - hp->str_size - += (sizeof (*str) + data_words * sizeof (uint64_t)) / s_ref_count; + word_t len = JSText_len(str); + size_t data_words = (len + 1) / 2; + hp->str_count += 1; + hp->str_size += sizeof(*str) + data_words * sizeof(uint64_t); } static void compute_bytecode_size (JSFunctionBytecode *b, @@ -5004,7 +4954,7 @@ static BOOL js_object_has_name (JSContext *ctx, JSValue obj) { JSValue val = rec->tab[slot].val; if (JS_VALUE_GET_TAG (val) != JS_TAG_STRING) return TRUE; JSText *p = JS_VALUE_GET_STRING (val); - return (p->len != 0); + return (JSText_len(p) != 0); } static int JS_DefineObjectName (JSContext *ctx, JSValue obj, JSValue name) { @@ -6023,23 +5973,25 @@ static JSValue JS_ToStringCheckObject (JSContext *ctx, JSValue val) { return JS_ToString (ctx, val); } -static JSValue JS_ToQuotedString (JSContext *ctx, JSValue val1) { +static JSValue JS_ToQuotedString(JSContext *ctx, JSValue val1) { JSValue val; JSText *p; int i; uint32_t c; - StringBuffer b_s, *b = &b_s; + JSText *b; char buf[16]; - val = JS_ToStringCheckObject (ctx, val1); - if (JS_IsException (val)) return val; - p = JS_VALUE_GET_STRING (val); + val = JS_ToStringCheckObject(ctx, val1); + if (JS_IsException(val)) return val; + p = JS_VALUE_GET_STRING(val); - if (string_buffer_init (ctx, b, p->len + 2)) goto fail; + b = pretext_init(ctx, (int)JSText_len(p) + 2); + if (!b) goto fail; - if (string_buffer_putc8 (b, '\"')) goto fail; - for (i = 0; i < p->len;) { - c = string_getc (p, &i); + b = pretext_putc8(ctx, b, '\"'); + if (!b) goto fail; + for (i = 0; i < (int)JSText_len(p);) { + c = string_getc(p, &i); switch (c) { case '\t': c = 't'; @@ -6059,24 +6011,29 @@ static JSValue JS_ToQuotedString (JSContext *ctx, JSValue val1) { case '\"': case '\\': quote: - if (string_buffer_putc8 (b, '\\')) goto fail; - if (string_buffer_putc8 (b, c)) goto fail; + b = pretext_putc8(ctx, b, '\\'); + if (!b) goto fail; + b = pretext_putc8(ctx, b, c); + if (!b) goto fail; break; default: - if (c < 32 || is_surrogate (c)) { - snprintf (buf, sizeof (buf), "\\u%04x", c); - if (string_buffer_puts8 (b, buf)) goto fail; + if (c < 32 || is_surrogate(c)) { + snprintf(buf, sizeof(buf), "\\u%04x", c); + b = pretext_puts8(ctx, b, buf); + if (!b) goto fail; } else { - if (string_buffer_putc (b, c)) goto fail; + b = pretext_putc(ctx, b, c); + if (!b) goto fail; } break; } } - if (string_buffer_putc8 (b, '\"')) goto fail; - JS_FreeValue (ctx, val); - return string_buffer_end (b); + b = pretext_putc8(ctx, b, '\"'); + if (!b) goto fail; + JS_FreeValue(ctx, val); + return pretext_end(ctx, b); fail: - JS_FreeValue (ctx, val); + JS_FreeValue(ctx, val); return JS_EXCEPTION; } @@ -6142,7 +6099,7 @@ static void js_print_string_rec (JSPrintValueState *s, JSValue val, int sep, JSText *p = JS_VALUE_GET_STRING (val); uint32_t i, len; if (pos < s->options.max_string_length) { - len = min_uint32 (p->len, s->options.max_string_length - pos); + len = min_uint32 ((uint32_t)JSText_len(p), s->options.max_string_length - pos); for (i = 0; i < len; i++) { js_dump_char (s, string_get (p, i), sep); } @@ -6162,14 +6119,7 @@ static void js_print_string_rec (JSPrintValueState *s, JSValue val, int sep, } static void js_print_string (JSPrintValueState *s, JSValue val) { - int sep; - if (s->options.raw_dump && JS_VALUE_GET_TAG (val) == JS_TAG_STRING) { - JSText *p = JS_VALUE_GET_STRING (val); - js_printf (s, "%d", p->header.ref_count); - sep = (p->header.ref_count == 1) ? '\"' : '\''; - } else { - sep = '\"'; - } + int sep = '\"'; js_putc (s, sep); js_print_string_rec (s, val, sep, 0); js_putc (s, sep); @@ -6197,9 +6147,10 @@ static void js_print_raw_string (JSPrintValueState *s, JSValue val) { static BOOL is_ascii_ident (const JSText *p) { int i, c; + int len = (int)JSText_len(p); - if (p->len == 0) return FALSE; - for (i = 0; i < p->len; i++) { + if (len == 0) return FALSE; + for (i = 0; i < len; i++) { c = string_get (p, i); if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0))) @@ -9308,7 +9259,7 @@ restart: int n, i; JSValue out; - n = get_u16 (pc); + n = get_u16(pc); pc += 2; if (n <= 0) { @@ -9316,35 +9267,39 @@ restart: BREAK; } - JSText *concat = string_buffer_init(ctx, size); - if (!concat) goto exception; + JSText *b = pretext_init(ctx, 64); + if (!b) goto exception; for (i = 0; i < n; i++) { JSValue v = sp[i - n]; - JSValue s = js_cell_text (ctx, JS_NULL, 1, &v); - if (JS_IsException (s)) { + JSValue s = js_cell_text(ctx, JS_NULL, 1, &v); + if (JS_IsException(s)) { + pretext_free(ctx, b); for (int j = 0; j < n; j++) - JS_FreeValue (ctx, sp[j - n]); + JS_FreeValue(ctx, sp[j - n]); sp -= n; goto exception; } - concat = text_concat(ctx, concat, s); - if (!concat) { + b = pretext_concat_value(ctx, b, s); + JS_FreeValue(ctx, s); + if (!b) { + for (int j = 0; j < n; j++) + JS_FreeValue(ctx, sp[j - n]); sp -= n; goto exception; } } - out = string_buffer_end (b); - if (JS_IsException (out)) { + out = pretext_end(ctx, b); + if (JS_IsException(out)) { for (int j = 0; j < n; j++) - JS_FreeValue (ctx, sp[j - n]); + JS_FreeValue(ctx, sp[j - n]); sp -= n; goto exception; } for (i = 0; i < n; i++) - JS_FreeValue (ctx, sp[i - n]); + JS_FreeValue(ctx, sp[i - n]); sp -= n; *sp++ = out; } @@ -9995,14 +9950,15 @@ static int js_parse_error_reserved_identifier (JSParseState *s) { JS_KeyGetStr (s->ctx, buf1, sizeof (buf1), s->token.u.ident.str)); } -static __exception int js_parse_template_part (JSParseState *s, - const uint8_t *p) { +static __exception int js_parse_template_part(JSParseState *s, + const uint8_t *p) { uint32_t c; - StringBuffer b_s, *b = &b_s; + JSText *b; JSValue str; /* p points to the first byte of the template part */ - if (string_buffer_init (s->ctx, b, 32)) goto fail; + b = pretext_init(s->ctx, 32); + if (!b) goto fail; for (;;) { if (p >= s->buf_end) goto unexpected_eof; c = *p++; @@ -10016,7 +9972,8 @@ static __exception int js_parse_template_part (JSParseState *s, break; } if (c == '\\') { - if (string_buffer_putc8 (b, c)) goto fail; + b = pretext_putc8(s->ctx, b, c); + if (!b) goto fail; if (p >= s->buf_end) goto unexpected_eof; c = *p++; } @@ -10027,17 +9984,18 @@ static __exception int js_parse_template_part (JSParseState *s, } if (c >= 0x80) { const uint8_t *p_next; - c = unicode_from_utf8 (p - 1, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { - js_parse_error_pos (s, p - 1, "invalid UTF-8 sequence"); + js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence"); goto fail; } p = p_next; } - if (string_buffer_putc (b, c)) goto fail; + b = pretext_putc(s->ctx, b, c); + if (!b) goto fail; } - str = string_buffer_end (b); - if (JS_IsException (str)) return -1; + str = pretext_end(s->ctx, b); + if (JS_IsException(str)) return -1; s->token.val = TOK_TEMPLATE; s->token.u.str.sep = c; s->token.u.str.str = str; @@ -10045,23 +10003,24 @@ static __exception int js_parse_template_part (JSParseState *s, return 0; unexpected_eof: - js_parse_error (s, "unexpected end of string"); + js_parse_error(s, "unexpected end of string"); fail: - string_buffer_free (b); + pretext_free(s->ctx, b); return -1; } -static __exception int js_parse_string (JSParseState *s, int sep, - BOOL do_throw, const uint8_t *p, - JSToken *token, const uint8_t **pp) { +static __exception int js_parse_string(JSParseState *s, int sep, + BOOL do_throw, const uint8_t *p, + JSToken *token, const uint8_t **pp) { int ret; uint32_t c; - StringBuffer b_s, *b = &b_s; + JSText *b; const uint8_t *p_escape; JSValue str; /* string */ - if (string_buffer_init (s->ctx, b, 32)) goto fail; + b = pretext_init(s->ctx, 32); + if (!b) goto fail; for (;;) { if (p >= s->buf_end) goto invalid_char; c = *p; @@ -10116,7 +10075,7 @@ static __exception int js_parse_string (JSParseState *s, int sep, goto invalid_escape; } else { if (do_throw) - js_parse_error_pos ( + js_parse_error_pos( s, p_escape, "octal escape sequences are not allowed in strict mode"); } @@ -10124,18 +10083,18 @@ static __exception int js_parse_string (JSParseState *s, int sep, } } else if (c >= 0x80) { const uint8_t *p_next; - c = unicode_from_utf8 (p, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { goto invalid_utf8; } p = p_next; /* LS or PS are skipped */ if (c == CP_LS || c == CP_PS) continue; } else { parse_escape: - ret = lre_parse_escape (&p, TRUE); + ret = lre_parse_escape(&p, TRUE); if (ret == -1) { invalid_escape: if (do_throw) - js_parse_error_pos ( + js_parse_error_pos( s, p_escape, "malformed escape sequence in string literal"); goto fail; } else if (ret < 0) { @@ -10149,14 +10108,15 @@ static __exception int js_parse_string (JSParseState *s, int sep, } } else if (c >= 0x80) { const uint8_t *p_next; - c = unicode_from_utf8 (p - 1, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) goto invalid_utf8; p = p_next; } - if (string_buffer_putc (b, c)) goto fail; + b = pretext_putc(s->ctx, b, c); + if (!b) goto fail; } - str = string_buffer_end (b); - if (JS_IsException (str)) return -1; + str = pretext_end(s->ctx, b); + if (JS_IsException(str)) return -1; token->val = TOK_STRING; token->u.str.sep = c; token->u.str.str = str; @@ -10164,12 +10124,12 @@ static __exception int js_parse_string (JSParseState *s, int sep, return 0; invalid_utf8: - if (do_throw) js_parse_error (s, "invalid UTF-8 sequence"); + if (do_throw) js_parse_error(s, "invalid UTF-8 sequence"); goto fail; invalid_char: - if (do_throw) js_parse_error (s, "unexpected end of string"); + if (do_throw) js_parse_error(s, "unexpected end of string"); fail: - string_buffer_free (b); + pretext_free(s->ctx, b); return -1; } @@ -10178,23 +10138,25 @@ static inline BOOL token_is_pseudo_keyword (JSParseState *s, JSValue key) { && !s->token.u.ident.has_escape; } -static __exception int js_parse_regexp (JSParseState *s) { +static __exception int js_parse_regexp(JSParseState *s) { const uint8_t *p; BOOL in_class; - StringBuffer b_s, *b = &b_s; - StringBuffer b2_s, *b2 = &b2_s; + JSText *b; + JSText *b2; uint32_t c; JSValue body_str, flags_str; p = s->buf_ptr; p++; in_class = FALSE; - if (string_buffer_init (s->ctx, b, 32)) return -1; - if (string_buffer_init (s->ctx, b2, 1)) goto fail; + b = pretext_init(s->ctx, 32); + if (!b) return -1; + b2 = pretext_init(s->ctx, 1); + if (!b2) goto fail; for (;;) { if (p >= s->buf_end) { eof_error: - js_parse_error (s, "unexpected end of regexp"); + js_parse_error(s, "unexpected end of regexp"); goto fail; } c = *p++; @@ -10208,7 +10170,8 @@ static __exception int js_parse_regexp (JSParseState *s) { /* XXX: incorrect as the first character in a class */ in_class = FALSE; } else if (c == '\\') { - if (string_buffer_putc8 (b, c)) goto fail; + b = pretext_putc8(s->ctx, b, c); + if (!b) goto fail; c = *p++; if (c == '\n' || c == '\r') goto eol_error; @@ -10216,28 +10179,29 @@ static __exception int js_parse_regexp (JSParseState *s) { goto eof_error; else if (c >= 0x80) { const uint8_t *p_next; - c = unicode_from_utf8 (p - 1, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { goto invalid_utf8; } p = p_next; if (c == CP_LS || c == CP_PS) goto eol_error; } } else if (c >= 0x80) { const uint8_t *p_next; - c = unicode_from_utf8 (p - 1, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { invalid_utf8: - js_parse_error_pos (s, p - 1, "invalid UTF-8 sequence"); + js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence"); goto fail; } /* LS or PS are considered as line terminator */ if (c == CP_LS || c == CP_PS) { eol_error: - js_parse_error_pos (s, p - 1, "unexpected line terminator in regexp"); + js_parse_error_pos(s, p - 1, "unexpected line terminator in regexp"); goto fail; } p = p_next; } - if (string_buffer_putc (b, c)) goto fail; + b = pretext_putc(s->ctx, b, c); + if (!b) goto fail; } /* flags */ @@ -10245,22 +10209,23 @@ static __exception int js_parse_regexp (JSParseState *s) { const uint8_t *p_next = p; c = *p_next++; if (c >= 0x80) { - c = unicode_from_utf8 (p, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { p++; goto invalid_utf8; } } - if (!lre_js_is_ident_next (c)) break; - if (string_buffer_putc (b2, c)) goto fail; + if (!lre_js_is_ident_next(c)) break; + b2 = pretext_putc(s->ctx, b2, c); + if (!b2) goto fail; p = p_next; } - body_str = string_buffer_end (b); - flags_str = string_buffer_end (b2); - if (JS_IsException (body_str) || JS_IsException (flags_str)) { - JS_FreeValue (s->ctx, body_str); - JS_FreeValue (s->ctx, flags_str); + body_str = pretext_end(s->ctx, b); + flags_str = pretext_end(s->ctx, b2); + if (JS_IsException(body_str) || JS_IsException(flags_str)) { + JS_FreeValue(s->ctx, body_str); + JS_FreeValue(s->ctx, flags_str); return -1; } s->token.val = TOK_REGEXP; @@ -10269,8 +10234,8 @@ static __exception int js_parse_regexp (JSParseState *s) { s->buf_ptr = p; return 0; fail: - string_buffer_free (b); - string_buffer_free (b2); + pretext_free(s->ctx, b); + pretext_free(s->ctx, b2); return -1; } @@ -10917,13 +10882,14 @@ done: return str; } -static int json_parse_string (JSParseState *s, const uint8_t **pp, int sep) { +static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep) { const uint8_t *p, *p_next; int i; uint32_t c; - StringBuffer b_s, *b = &b_s; + JSText *b; - if (string_buffer_init (s->ctx, b, 32)) goto fail; + b = pretext_init(s->ctx, 32); + if (!b) goto fail; p = *pp; for (;;) { @@ -10931,7 +10897,7 @@ static int json_parse_string (JSParseState *s, const uint8_t **pp, int sep) { c = *p++; if (c == sep) break; if (c < 0x20) { - js_parse_error_pos (s, p - 1, "Bad control character in string literal"); + js_parse_error_pos(s, p - 1, "Bad control character in string literal"); goto fail; } if (c == '\\') { @@ -10959,9 +10925,9 @@ static int json_parse_string (JSParseState *s, const uint8_t **pp, int sep) { case 'u': c = 0; for (i = 0; i < 4; i++) { - int h = from_hex (*p++); + int h = from_hex(*p++); if (h < 0) { - js_parse_error_pos (s, p - 1, "Bad Unicode escape"); + js_parse_error_pos(s, p - 1, "Bad Unicode escape"); goto fail; } c = (c << 4) | h; @@ -10980,29 +10946,30 @@ static int json_parse_string (JSParseState *s, const uint8_t **pp, int sep) { if (c == sep) break; if (p > s->buf_end) goto end_of_input; bad_escape: - js_parse_error_pos (s, p - 1, "Bad escaped character"); + js_parse_error_pos(s, p - 1, "Bad escaped character"); goto fail; } } else if (c >= 0x80) { - c = unicode_from_utf8 (p - 1, UTF8_CHAR_LEN_MAX, &p_next); + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { - js_parse_error_pos (s, p - 1, "Bad UTF-8 sequence"); + js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence"); goto fail; } p = p_next; } - if (string_buffer_putc (b, c)) goto fail; + b = pretext_putc(s->ctx, b, c); + if (!b) goto fail; } s->token.val = TOK_STRING; s->token.u.str.sep = sep; - s->token.u.str.str = string_buffer_end (b); + s->token.u.str.str = pretext_end(s->ctx, b); *pp = p; return 0; end_of_input: - js_parse_error (s, "Unexpected end of JSON input"); + js_parse_error(s, "Unexpected end of JSON input"); fail: - string_buffer_free (b); + pretext_free(s->ctx, b); return -1; } @@ -11967,9 +11934,9 @@ static __exception int js_parse_template (JSParseState *s, int call, */ JS_FreeValue (ctx, s->token.u.str.str); s->token.u.str.str = JS_NULL; - if (js_parse_string (s, '`', TRUE, p, &cooked, &p)) return -1; - str = JS_VALUE_GET_STRING (cooked.u.str.str); - if (str->len != 0 || depth == 0) { + if (js_parse_string(s, '`', TRUE, p, &cooked, &p)) return -1; + str = JS_VALUE_GET_STRING(cooked.u.str.str); + if (JSText_len(str) != 0 || depth == 0) { ret = emit_push_const (s, cooked.u.str.str); JS_FreeValue (s->ctx, cooked.u.str.str); if (ret) return -1; @@ -18880,7 +18847,7 @@ static int bc_put_key (BCWriterState *s, JSValue key) { JSText *p = JS_VALUE_GET_STRING (key); /* Write as UTF-8 */ - uint32_t len = p->len; + uint32_t len = (uint32_t)JSText_len(p); /* Calculate UTF-8 size */ size_t utf8_size = 0; for (uint32_t i = 0; i < len; i++) { @@ -19003,9 +18970,10 @@ fail: static void JS_WriteString (BCWriterState *s, JSText *p) { int i; + int len = (int)JSText_len(p); /* UTF-32: write length, then each character as 32-bit value */ - bc_put_leb128 (s, (uint32_t)p->len); - for (i = 0; i < p->len; i++) { + bc_put_leb128 (s, (uint32_t)len); + for (i = 0; i < len; i++) { uint32_t c = string_get (p, i); bc_put_u32 (s, c); } @@ -20080,7 +20048,7 @@ static __exception int js_get_length32 (JSContext *ctx, uint32_t *pres, if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) { JSText *p = JS_VALUE_GET_STRING (obj); - *pres = p->len; + *pres = JSText_len(p); return 0; } @@ -20544,25 +20512,28 @@ fail: return JS_EXCEPTION; } -static JSValue js_regexp_toString (JSContext *ctx, JSValue this_val, int argc, - JSValue *argv) { +static JSValue js_regexp_toString(JSContext *ctx, JSValue this_val, int argc, + JSValue *argv) { JSValue pattern, flags; - StringBuffer b_s, *b = &b_s; - if (!JS_IsObject (this_val)) return JS_ThrowTypeErrorNotAnObject (ctx); + if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); - JSText *text = js_alloc_string(ctx, 0); + JSText *b = pretext_init(ctx, 0); + if (!b) return JS_EXCEPTION; - text_putc(ctx, text, '/'); - pattern = JS_GetProperty (ctx, this_val, JS_KEY_source); - text = text_concat(ctx, text, pattern); - text_putc(ctx, text, '/'); - flags = JS_GetProperty (ctx, this_val, JS_KEY_flags); - text = text_concat(ctx, text, flags); - return text_concat_end(text); - -fail: - return JS_EXCEPTION; + b = pretext_putc(ctx, b, '/'); + if (!b) return JS_EXCEPTION; + pattern = JS_GetProperty(ctx, this_val, JS_KEY_source); + b = pretext_concat_value(ctx, b, pattern); + JS_FreeValue(ctx, pattern); + if (!b) return JS_EXCEPTION; + b = pretext_putc(ctx, b, '/'); + if (!b) return JS_EXCEPTION; + flags = JS_GetProperty(ctx, this_val, JS_KEY_flags); + b = pretext_concat_value(ctx, b, flags); + JS_FreeValue(ctx, flags); + if (!b) return JS_EXCEPTION; + return pretext_end(ctx, b); } int lre_check_stack_overflow (void *opaque, size_t alloca_size) { @@ -20586,16 +20557,16 @@ void *lre_realloc (void *opaque, void *ptr, size_t size) { /* Convert UTF-32 JSText to UTF-16 buffer for regex engine. Returns allocated uint16_t buffer that must be freed by caller. Sets *out_len to number of uint16 code units. */ -static uint16_t *js_string_to_utf16 (JSContext *ctx, JSText *str, - int *out_len) { - int len = str->len; +static uint16_t *js_string_to_utf16(JSContext *ctx, JSText *str, + int *out_len) { + int len = (int)JSText_len(str); /* Worst case: each UTF-32 char becomes 2 UTF-16 surrogates */ - uint16_t *buf = js_malloc (ctx, len * 2 * sizeof (uint16_t)); + uint16_t *buf = js_malloc(ctx, len * 2 * sizeof(uint16_t)); if (!buf) return NULL; int j = 0; for (int i = 0; i < len; i++) { - uint32_t c = string_get (str, i); + uint32_t c = string_get(str, i); if (c < 0x10000) { buf[j++] = (uint16_t)c; } else { @@ -20656,11 +20627,11 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, shift = 1; /* UTF-16 mode */ str_buf = (uint8_t *)utf16_buf; - if (last_index > str->len) { + if (last_index > (int)JSText_len(str)) { rc = 2; } else { - rc = lre_exec (capture, re_bytecode, str_buf, last_index, str->len, shift, - ctx); + rc = lre_exec(capture, re_bytecode, str_buf, last_index, (int)JSText_len(str), shift, + ctx); } if (rc != 1) { @@ -20796,9 +20767,9 @@ fail: } /* delete portions of a string that match a given regex */ -static JSValue JS_RegExpDelete (JSContext *ctx, JSValue this_val, - JSValue arg) { - JSRegExp *re = js_get_regexp (ctx, this_val, TRUE); +static JSValue JS_RegExpDelete(JSContext *ctx, JSValue this_val, + JSValue arg) { + JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); JSText *str; JSValue str_val, val; uint8_t *re_bytecode; @@ -20809,32 +20780,33 @@ static JSValue JS_RegExpDelete (JSContext *ctx, JSValue this_val, int capture_count, shift, re_flags; int next_src_pos, start, end; int64_t last_index; - StringBuffer b_s, *b = &b_s; + JSText *b; if (!re) return JS_EXCEPTION; - string_buffer_init (ctx, b, 0); + b = pretext_init(ctx, 0); + if (!b) return JS_EXCEPTION; capture = NULL; - str_val = JS_ToString (ctx, arg); - if (JS_IsException (str_val)) goto fail; - str = JS_VALUE_GET_STRING (str_val); + str_val = JS_ToString(ctx, arg); + if (JS_IsException(str_val)) goto fail; + str = JS_VALUE_GET_STRING(str_val); re_bytecode = (uint8_t *)re->bytecode->u; - re_flags = lre_get_flags (re_bytecode); + re_flags = lre_get_flags(re_bytecode); if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) { last_index = 0; } else { - val = JS_GetPropertyStr (ctx, this_val, "lastIndex"); - if (JS_IsException (val) || JS_ToLengthFree (ctx, &last_index, val)) + val = JS_GetPropertyStr(ctx, this_val, "lastIndex"); + if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val)) goto fail; } - capture_count = lre_get_capture_count (re_bytecode); + capture_count = lre_get_capture_count(re_bytecode); if (capture_count > 0) { - capture = js_malloc (ctx, sizeof (capture[0]) * capture_count * 2); + capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2); if (!capture) goto fail; } /* Convert UTF-32 string to UTF-16 for regex engine */ - utf16_buf = js_string_to_utf16 (ctx, str, &utf16_len); + utf16_buf = js_string_to_utf16(ctx, str, &utf16_len); if (!utf16_buf) goto fail; shift = 1; /* UTF-16 mode */ str_buf = (uint8_t *)utf16_buf; @@ -20842,21 +20814,21 @@ static JSValue JS_RegExpDelete (JSContext *ctx, JSValue this_val, for (;;) { if (last_index > utf16_len) break; - ret = lre_exec (capture, re_bytecode, str_buf, last_index, utf16_len, - shift, ctx); + ret = lre_exec(capture, re_bytecode, str_buf, last_index, utf16_len, + shift, ctx); if (ret != 1) { if (ret >= 0) { if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { - if (JS_SetPropertyStr (ctx, this_val, "lastIndex", - JS_NewInt32 (ctx, 0)) + if (JS_SetPropertyStr(ctx, this_val, "lastIndex", + JS_NewInt32(ctx, 0)) < 0) goto fail; } } else { if (ret == LRE_RET_TIMEOUT) { - JS_ThrowInterrupted (ctx); + JS_ThrowInterrupted(ctx); } else { - JS_ThrowInternalError (ctx, "out of memory in regexp execution"); + JS_ThrowInternalError(ctx, "out of memory in regexp execution"); } goto fail; } @@ -20866,12 +20838,13 @@ static JSValue JS_RegExpDelete (JSContext *ctx, JSValue this_val, end = (capture[1] - str_buf) >> shift; last_index = end; if (next_src_pos < start) { - if (string_buffer_concat (b, str, next_src_pos, start)) goto fail; + b = pretext_concat(ctx, b, str, next_src_pos, start); + if (!b) goto fail; } next_src_pos = end; if (!(re_flags & LRE_FLAG_GLOBAL)) { - if (JS_SetPropertyStr (ctx, this_val, "lastIndex", - JS_NewInt32 (ctx, end)) + if (JS_SetPropertyStr(ctx, this_val, "lastIndex", + JS_NewInt32(ctx, end)) < 0) goto fail; break; @@ -20884,24 +20857,25 @@ static JSValue JS_RegExpDelete (JSContext *ctx, JSValue this_val, /* Check for surrogate pair in UTF-16 buffer */ uint16_t c = utf16_buf[end]; end++; - if (is_hi_surrogate (c) && end < utf16_len - && is_lo_surrogate (utf16_buf[end])) { + if (is_hi_surrogate(c) && end < utf16_len + && is_lo_surrogate(utf16_buf[end])) { end++; } } } last_index = end; } - if (string_buffer_concat (b, str, next_src_pos, str->len)) goto fail; - JS_FreeValue (ctx, str_val); - js_free (ctx, capture); - js_free (ctx, utf16_buf); - return string_buffer_end (b); + b = pretext_concat(ctx, b, str, next_src_pos, (uint32_t)JSText_len(str)); + if (!b) goto fail; + JS_FreeValue(ctx, str_val); + js_free(ctx, capture); + js_free(ctx, utf16_buf); + return pretext_end(ctx, b); fail: - JS_FreeValue (ctx, str_val); - js_free (ctx, capture); - js_free (ctx, utf16_buf); - string_buffer_free (b); + JS_FreeValue(ctx, str_val); + js_free(ctx, capture); + js_free(ctx, utf16_buf); + pretext_free(ctx, b); return JS_EXCEPTION; } @@ -21188,12 +21162,13 @@ static JSValue js_json_parse (JSContext *ctx, JSValue this_val, int argc, } typedef struct JSONStringifyContext { + JSContext *ctx; JSValue replacer_func; JSValue stack; JSValue property_list; JSValue gap; JSValue empty; - StringBuffer *b; + JSText *b; } JSONStringifyContext; static JSValue JS_ToQuotedStringFree (JSContext *ctx, JSValue val) { @@ -21254,8 +21229,8 @@ exception: return JS_EXCEPTION; } -static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, - JSValue holder, JSValue val, JSValue indent) { +static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, + JSValue holder, JSValue val, JSValue indent) { JSValue indent1, sep, sep1, tab, v, prop; JSRecord *p; int64_t i, len; @@ -21268,154 +21243,175 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, tab = JS_NULL; prop = JS_NULL; - if (js_check_stack_overflow (ctx->rt, 0)) { - JS_ThrowStackOverflow (ctx); + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); goto exception; } - if (JS_IsObject ( + if (JS_IsObject( val)) { /* includes arrays (OBJ_ARRAY) since they have JS_TAG_OBJECT */ - v = js_array_includes (ctx, jsc->stack, 1, (JSValue *)&val); - if (JS_IsException (v)) goto exception; - if (JS_ToBoolFree (ctx, v)) { - JS_ThrowTypeError (ctx, "circular reference"); + v = js_array_includes(ctx, jsc->stack, 1, (JSValue *)&val); + if (JS_IsException(v)) goto exception; + if (JS_ToBoolFree(ctx, v)) { + JS_ThrowTypeError(ctx, "circular reference"); goto exception; } - indent1 = JS_ConcatString (ctx, JS_DupValue (ctx, indent), - JS_DupValue (ctx, jsc->gap)); - if (JS_IsException (indent1)) goto exception; - if (!JS_IsEmptyString (jsc->gap)) { - sep = JS_ConcatString3 (ctx, "\n", JS_DupValue (ctx, indent1), ""); - if (JS_IsException (sep)) goto exception; - sep1 = js_new_string8 (ctx, " "); - if (JS_IsException (sep1)) goto exception; + indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), + JS_DupValue(ctx, jsc->gap)); + if (JS_IsException(indent1)) goto exception; + if (!JS_IsEmptyString(jsc->gap)) { + sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), ""); + if (JS_IsException(sep)) goto exception; + sep1 = js_new_string8(ctx, " "); + if (JS_IsException(sep1)) goto exception; } else { - sep = JS_DupValue (ctx, jsc->empty); - sep1 = JS_DupValue (ctx, jsc->empty); + sep = JS_DupValue(ctx, jsc->empty); + sep1 = JS_DupValue(ctx, jsc->empty); } - v = js_cell_push (ctx, jsc->stack, 1, (JSValue *)&val); - if (check_exception_free (ctx, v)) goto exception; - ret = JS_IsArray (ctx, val); + v = js_cell_push(ctx, jsc->stack, 1, (JSValue *)&val); + if (check_exception_free(ctx, v)) goto exception; + ret = JS_IsArray(ctx, val); if (ret < 0) goto exception; if (ret) { - if (js_get_length64 (ctx, &len, val)) goto exception; - string_buffer_putc8 (jsc->b, '['); + if (js_get_length64(ctx, &len, val)) goto exception; + jsc->b = pretext_putc8(ctx, jsc->b, '['); + if (!jsc->b) goto exception; for (i = 0; i < len; i++) { - if (i > 0) string_buffer_putc8 (jsc->b, ','); - string_buffer_concat_value (jsc->b, sep); - v = JS_GetPropertyInt64 (ctx, val, i); - if (JS_IsException (v)) goto exception; + if (i > 0) { + jsc->b = pretext_putc8(ctx, jsc->b, ','); + if (!jsc->b) goto exception; + } + jsc->b = pretext_concat_value(ctx, jsc->b, sep); + if (!jsc->b) goto exception; + v = JS_GetPropertyInt64(ctx, val, i); + if (JS_IsException(v)) goto exception; /* XXX: could do this string conversion only when needed */ - prop = JS_ToStringFree (ctx, JS_NewInt64 (ctx, i)); - if (JS_IsException (prop)) goto exception; - v = js_json_check (ctx, jsc, val, v, prop); - JS_FreeValue (ctx, prop); + prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i)); + if (JS_IsException(prop)) goto exception; + v = js_json_check(ctx, jsc, val, v, prop); + JS_FreeValue(ctx, prop); prop = JS_NULL; - if (JS_IsException (v)) goto exception; - if (JS_IsNull (v)) v = JS_NULL; - if (js_json_to_str (ctx, jsc, val, v, indent1)) goto exception; + if (JS_IsException(v)) goto exception; + if (JS_IsNull(v)) v = JS_NULL; + if (js_json_to_str(ctx, jsc, val, v, indent1)) goto exception; } - if (len > 0 && !JS_IsEmptyString (jsc->gap)) { - string_buffer_putc8 (jsc->b, '\n'); - string_buffer_concat_value (jsc->b, indent); + if (len > 0 && !JS_IsEmptyString(jsc->gap)) { + jsc->b = pretext_putc8(ctx, jsc->b, '\n'); + if (!jsc->b) goto exception; + jsc->b = pretext_concat_value(ctx, jsc->b, indent); + if (!jsc->b) goto exception; } - string_buffer_putc8 (jsc->b, ']'); + jsc->b = pretext_putc8(ctx, jsc->b, ']'); + if (!jsc->b) goto exception; } else { - if (!JS_IsNull (jsc->property_list)) - tab = JS_DupValue (ctx, jsc->property_list); + if (!JS_IsNull(jsc->property_list)) + tab = JS_DupValue(ctx, jsc->property_list); else - tab = JS_GetOwnPropertyNames (ctx, val); - if (JS_IsException (tab)) goto exception; - if (js_get_length64 (ctx, &len, tab)) goto exception; - string_buffer_putc8 (jsc->b, '{'); + tab = JS_GetOwnPropertyNames(ctx, val); + if (JS_IsException(tab)) goto exception; + if (js_get_length64(ctx, &len, tab)) goto exception; + jsc->b = pretext_putc8(ctx, jsc->b, '{'); + if (!jsc->b) goto exception; has_content = FALSE; for (i = 0; i < len; i++) { - JS_FreeValue (ctx, prop); - prop = JS_GetPropertyInt64 (ctx, tab, i); - if (JS_IsException (prop)) goto exception; - v = JS_GetPropertyValue (ctx, val, JS_DupValue (ctx, prop)); - if (JS_IsException (v)) goto exception; - v = js_json_check (ctx, jsc, val, v, prop); - if (JS_IsException (v)) goto exception; - if (!JS_IsNull (v)) { - if (has_content) string_buffer_putc8 (jsc->b, ','); - prop = JS_ToQuotedStringFree (ctx, prop); - if (JS_IsException (prop)) { - JS_FreeValue (ctx, v); + JS_FreeValue(ctx, prop); + prop = JS_GetPropertyInt64(ctx, tab, i); + if (JS_IsException(prop)) goto exception; + v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop)); + if (JS_IsException(v)) goto exception; + v = js_json_check(ctx, jsc, val, v, prop); + if (JS_IsException(v)) goto exception; + if (!JS_IsNull(v)) { + if (has_content) { + jsc->b = pretext_putc8(ctx, jsc->b, ','); + if (!jsc->b) goto exception; + } + prop = JS_ToQuotedStringFree(ctx, prop); + if (JS_IsException(prop)) { + JS_FreeValue(ctx, v); goto exception; } - string_buffer_concat_value (jsc->b, sep); - string_buffer_concat_value (jsc->b, prop); - string_buffer_putc8 (jsc->b, ':'); - string_buffer_concat_value (jsc->b, sep1); - if (js_json_to_str (ctx, jsc, val, v, indent1)) goto exception; + jsc->b = pretext_concat_value(ctx, jsc->b, sep); + if (!jsc->b) goto exception; + jsc->b = pretext_concat_value(ctx, jsc->b, prop); + if (!jsc->b) goto exception; + jsc->b = pretext_putc8(ctx, jsc->b, ':'); + if (!jsc->b) goto exception; + jsc->b = pretext_concat_value(ctx, jsc->b, sep1); + if (!jsc->b) goto exception; + if (js_json_to_str(ctx, jsc, val, v, indent1)) goto exception; has_content = TRUE; } } - if (has_content && !JS_IsEmptyString (jsc->gap)) { - string_buffer_putc8 (jsc->b, '\n'); - string_buffer_concat_value (jsc->b, indent); + if (has_content && !JS_IsEmptyString(jsc->gap)) { + jsc->b = pretext_putc8(ctx, jsc->b, '\n'); + if (!jsc->b) goto exception; + jsc->b = pretext_concat_value(ctx, jsc->b, indent); + if (!jsc->b) goto exception; } - string_buffer_putc8 (jsc->b, '}'); + jsc->b = pretext_putc8(ctx, jsc->b, '}'); + if (!jsc->b) goto exception; } - if (check_exception_free (ctx, js_cell_pop (ctx, jsc->stack, 0, NULL))) + if (check_exception_free(ctx, js_cell_pop(ctx, jsc->stack, 0, NULL))) goto exception; - JS_FreeValue (ctx, val); - JS_FreeValue (ctx, tab); - JS_FreeValue (ctx, sep); - JS_FreeValue (ctx, sep1); - JS_FreeValue (ctx, indent1); - JS_FreeValue (ctx, prop); + JS_FreeValue(ctx, val); + JS_FreeValue(ctx, tab); + JS_FreeValue(ctx, sep); + JS_FreeValue(ctx, sep1); + JS_FreeValue(ctx, indent1); + JS_FreeValue(ctx, prop); return 0; } concat_primitive: - switch (JS_VALUE_GET_NORM_TAG (val)) { + switch (JS_VALUE_GET_NORM_TAG(val)) { case JS_TAG_STRING: case JS_TAG_STRING_IMM: - val = JS_ToQuotedStringFree (ctx, val); - if (JS_IsException (val)) goto exception; + val = JS_ToQuotedStringFree(ctx, val); + if (JS_IsException(val)) goto exception; goto concat_value; case JS_TAG_FLOAT64: - if (!isfinite (JS_VALUE_GET_FLOAT64 (val))) { val = JS_NULL; } + if (!isfinite(JS_VALUE_GET_FLOAT64(val))) { val = JS_NULL; } goto concat_value; case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: concat_value: - return string_buffer_concat_value_free (jsc->b, val); + jsc->b = pretext_concat_value_free(ctx, jsc->b, val); + return jsc->b ? 0 : -1; default: - JS_FreeValue (ctx, val); + JS_FreeValue(ctx, val); return 0; } exception: - JS_FreeValue (ctx, val); - JS_FreeValue (ctx, tab); - JS_FreeValue (ctx, sep); - JS_FreeValue (ctx, sep1); - JS_FreeValue (ctx, indent1); - JS_FreeValue (ctx, prop); + JS_FreeValue(ctx, val); + JS_FreeValue(ctx, tab); + JS_FreeValue(ctx, sep); + JS_FreeValue(ctx, sep1); + JS_FreeValue(ctx, indent1); + JS_FreeValue(ctx, prop); return -1; } -JSValue JS_JSONStringify (JSContext *ctx, JSValue obj, JSValue replacer, - JSValue space0) { - StringBuffer b_s; +JSValue JS_JSONStringify(JSContext *ctx, JSValue obj, JSValue replacer, + JSValue space0) { JSONStringifyContext jsc_s, *jsc = &jsc_s; JSValue val, v, space, ret, wrapper; int res; int64_t i, j, n; + jsc->ctx = ctx; jsc->replacer_func = JS_NULL; jsc->stack = JS_NULL; jsc->property_list = JS_NULL; jsc->gap = JS_NULL; - jsc->b = &b_s; + jsc->b = NULL; jsc->empty = JS_KEY_empty; ret = JS_NULL; wrapper = JS_NULL; - string_buffer_init (ctx, jsc->b, 0); + jsc->b = pretext_init(ctx, 0); + if (!jsc->b) goto exception; jsc->stack = JS_NewArray (ctx); if (JS_IsException (jsc->stack)) goto exception; if (JS_IsFunction (replacer)) { @@ -21464,7 +21460,7 @@ JSValue JS_JSONStringify (JSContext *ctx, JSValue obj, JSValue replacer, jsc->gap = js_new_string8_len (ctx, " ", n); } else if (JS_IsText (space)) { JSText *p = JS_VALUE_GET_STRING (space); - jsc->gap = js_sub_string (ctx, p, 0, min_int (p->len, 10)); + jsc->gap = js_sub_string (ctx, p, 0, min_int ((int)JSText_len(p), 10)); } else { jsc->gap = JS_DupValue (ctx, jsc->empty); } @@ -21484,21 +21480,22 @@ JSValue JS_JSONStringify (JSContext *ctx, JSValue obj, JSValue replacer, ret = JS_NULL; goto done1; } - if (js_json_to_str (ctx, jsc, wrapper, val, jsc->empty)) goto exception; + if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty)) goto exception; - ret = string_buffer_end (jsc->b); + ret = pretext_end(ctx, jsc->b); + jsc->b = NULL; goto done; exception: ret = JS_EXCEPTION; done1: - string_buffer_free (jsc->b); + pretext_free(ctx, jsc->b); done: - JS_FreeValue (ctx, wrapper); - JS_FreeValue (ctx, jsc->empty); - JS_FreeValue (ctx, jsc->gap); - JS_FreeValue (ctx, jsc->property_list); - JS_FreeValue (ctx, jsc->stack); + JS_FreeValue(ctx, wrapper); + JS_FreeValue(ctx, jsc->empty); + JS_FreeValue(ctx, jsc->gap); + JS_FreeValue(ctx, jsc->property_list); + JS_FreeValue(ctx, jsc->stack); return ret; } @@ -22222,7 +22219,7 @@ static JSValue js_cell_character (JSContext *ctx, JSValue this_val, int argc, /* Handle string - return first character */ if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) { JSText *p = JS_VALUE_GET_STRING (arg); - if (p->len == 0) return JS_NewString (ctx, ""); + if (JSText_len(p) == 0) return JS_NewString (ctx, ""); /* UTF-32: each element is a full code point, no surrogate handling needed */ @@ -22299,7 +22296,7 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, if (argc == 1) return str; JSText *p = JS_VALUE_GET_STRING (str); - int len = p->len; + int len = (int)JSText_len(p); if (argc >= 2) { int tag1 = JS_VALUE_GET_TAG (argv[1]); @@ -22467,37 +22464,42 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, sep_alloc = TRUE; } - StringBuffer b_s, *b = &b_s; - string_buffer_init (ctx, b, 0); + JSText *b = pretext_init(ctx, 0); + if (!b) { + if (sep_alloc) JS_FreeCString(ctx, separator); + return JS_EXCEPTION; + } for (int64_t i = 0; i < len; i++) { if (i > 0 && separator[0]) { - if (string_buffer_puts8 (b, separator)) goto array_fail; + b = pretext_puts8(ctx, b, separator); + if (!b) goto array_fail; } - JSValue item = JS_GetPropertyInt64 (ctx, arg, i); - if (JS_IsException (item)) goto array_fail; + JSValue item = JS_GetPropertyInt64(ctx, arg, i); + if (JS_IsException(item)) goto array_fail; - if (!JS_VALUE_IS_TEXT (item)) { - JS_FreeValue (ctx, item); - string_buffer_free (b); - if (sep_alloc) JS_FreeCString (ctx, separator); - return JS_ThrowTypeError (ctx, "text: array element is not a string"); + if (!JS_VALUE_IS_TEXT(item)) { + JS_FreeValue(ctx, item); + pretext_free(ctx, b); + if (sep_alloc) JS_FreeCString(ctx, separator); + return JS_ThrowTypeError(ctx, "text: array element is not a string"); } - JSValue item_str = JS_ToString (ctx, item); - JS_FreeValue (ctx, item); - if (JS_IsException (item_str)) goto array_fail; + JSValue item_str = JS_ToString(ctx, item); + JS_FreeValue(ctx, item); + if (JS_IsException(item_str)) goto array_fail; - if (string_buffer_concat_value_free (b, item_str)) goto array_fail; + b = pretext_concat_value_free(ctx, b, item_str); + if (!b) goto array_fail; } - if (sep_alloc) JS_FreeCString (ctx, separator); - return string_buffer_end (b); + if (sep_alloc) JS_FreeCString(ctx, separator); + return pretext_end(ctx, b); array_fail: - string_buffer_free (b); - if (sep_alloc) JS_FreeCString (ctx, separator); + pretext_free(ctx, b); + if (sep_alloc) JS_FreeCString(ctx, separator); return JS_EXCEPTION; } @@ -22550,47 +22552,43 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, } /* text.lower(str) - convert to lowercase */ -static JSValue js_cell_text_lower (JSContext *ctx, JSValue this_val, int argc, - JSValue *argv) { +static JSValue js_cell_text_lower(JSContext *ctx, JSValue this_val, int argc, + JSValue *argv) { if (argc < 1) return JS_NULL; - if (!JS_VALUE_IS_TEXT (argv[0])) return JS_NULL; + if (!JS_VALUE_IS_TEXT(argv[0])) return JS_NULL; - JSText *p = JS_VALUE_GET_STRING (argv[0]); - StringBuffer b_s, *b = &b_s; - string_buffer_init (ctx, b, p->len); + JSText *p = JS_VALUE_GET_STRING(argv[0]); + JSText *b = pretext_init(ctx, (int)JSText_len(p)); + if (!b) return JS_EXCEPTION; - for (int i = 0; i < p->len; i++) { - uint32_t c = string_get (p, i); + for (int i = 0; i < (int)JSText_len(p); i++) { + uint32_t c = string_get(p, i); if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; - if (string_buffer_putc (b, c)) { - string_buffer_free (b); - return JS_EXCEPTION; - } + b = pretext_putc(ctx, b, c); + if (!b) return JS_EXCEPTION; } - return string_buffer_end (b); + return pretext_end(ctx, b); } /* text.upper(str) - convert to uppercase */ -static JSValue js_cell_text_upper (JSContext *ctx, JSValue this_val, int argc, - JSValue *argv) { +static JSValue js_cell_text_upper(JSContext *ctx, JSValue this_val, int argc, + JSValue *argv) { if (argc < 1) return JS_NULL; - if (!JS_VALUE_IS_TEXT (argv[0])) return JS_NULL; + if (!JS_VALUE_IS_TEXT(argv[0])) return JS_NULL; - JSText *p = JS_VALUE_GET_STRING (argv[0]); - StringBuffer b_s, *b = &b_s; - string_buffer_init (ctx, b, p->len); + JSText *p = JS_VALUE_GET_STRING(argv[0]); + JSText *b = pretext_init(ctx, (int)JSText_len(p)); + if (!b) return JS_EXCEPTION; - for (int i = 0; i < p->len; i++) { - uint32_t c = string_get (p, i); + for (int i = 0; i < (int)JSText_len(p); i++) { + uint32_t c = string_get(p, i); if (c >= 'a' && c <= 'z') c = c - 'a' + 'A'; - if (string_buffer_putc (b, c)) { - string_buffer_free (b); - return JS_EXCEPTION; - } + b = pretext_putc(ctx, b, c); + if (!b) return JS_EXCEPTION; } - return string_buffer_end (b); + return pretext_end(ctx, b); } /* text.trim(str, reject) - trim whitespace or custom characters */ @@ -22605,7 +22603,7 @@ static JSValue js_cell_text_trim (JSContext *ctx, JSValue this_val, int argc, JSText *p = JS_VALUE_GET_STRING (str); int start = 0; - int end = p->len; + int end = (int)JSText_len(p); if (argc > 1 && !JS_IsNull (argv[1])) { /* Custom trim with reject characters */ @@ -22665,14 +22663,15 @@ static JSValue js_cell_text_codepoint (JSContext *ctx, JSValue this_val, if (JS_IsException (str)) return str; JSText *p = JS_VALUE_GET_STRING (str); - if (p->len == 0) { + int plen = (int)JSText_len(p); + if (plen == 0) { /* str removed - arg not owned */ return JS_NULL; } uint32_t c = string_get (p, 0); /* Handle surrogate pairs */ - if (c >= 0xD800 && c <= 0xDBFF && p->len > 1) { + if (c >= 0xD800 && c <= 0xDBFF && plen > 1) { uint32_t c2 = string_get (p, 1); if (c2 >= 0xDC00 && c2 <= 0xDFFF) { c = 0x10000 + ((c - 0xD800) << 10) + (c2 - 0xDC00); @@ -22686,13 +22685,12 @@ static JSValue js_cell_text_codepoint (JSContext *ctx, JSValue this_val, /* Helpers (C, not C++). Put these above js_cell_text_replace in the same C * file. */ -static int sb_concat_value_to_string_free (JSContext *ctx, StringBuffer *b, - JSValue v) { - JSValue s = JS_ToString (ctx, v); - JS_FreeValue (ctx, v); - if (JS_IsException (s)) return -1; - if (string_buffer_concat_value_free (b, s)) return -1; - return 0; +static JSText *pt_concat_value_to_string_free(JSContext *ctx, JSText *b, JSValue v) { + JSValue s = JS_ToString(ctx, v); + JS_FreeValue(ctx, v); + if (JS_IsException(s)) return NULL; + b = pretext_concat_value_free(ctx, b, s); + return b; } /* Build replacement for a match at `found`. @@ -22750,48 +22748,48 @@ static int JS_IsRegExp (JSContext *ctx, JSValue v) { * limit even if replacement returns null. */ -static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) { +static JSValue js_cell_text_replace(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { if (argc < 2) return JS_NULL; - int tag_text = JS_VALUE_GET_TAG (argv[0]); + int tag_text = JS_VALUE_GET_TAG(argv[0]); if (tag_text != JS_TAG_STRING && tag_text != JS_TAG_STRING_IMM) return JS_NULL; int target_is_regex = 0; { - int tag_tgt = JS_VALUE_GET_TAG (argv[1]); + int tag_tgt = JS_VALUE_GET_TAG(argv[1]); if (tag_tgt == JS_TAG_STRING || tag_tgt == JS_TAG_STRING_IMM) { target_is_regex = 0; - } else if (JS_IsObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) { + } else if (JS_IsObject(argv[1]) && JS_IsRegExp(ctx, argv[1])) { target_is_regex = 1; } else { return JS_NULL; } } - if (!JS_VALUE_IS_TEXT (argv[0])) - return JS_ThrowInternalError (ctx, "Replace must have text in arg0."); + if (!JS_VALUE_IS_TEXT(argv[0])) + return JS_ThrowInternalError(ctx, "Replace must have text in arg0."); - JSText *sp = JS_VALUE_GET_STRING (argv[0]); - int len = (int)sp->len; + JSText *sp = JS_VALUE_GET_STRING(argv[0]); + int len = (int)JSText_len(sp); int32_t limit = -1; - if (argc > 3 && !JS_IsNull (argv[3])) { - if (JS_ToInt32 (ctx, &limit, argv[3])) { return JS_NULL; } + if (argc > 3 && !JS_IsNull(argv[3])) { + if (JS_ToInt32(ctx, &limit, argv[3])) { return JS_NULL; } if (limit < 0) limit = -1; } - StringBuffer b_s, *b = &b_s; - string_buffer_init (ctx, b, len); + JSText *b = pretext_init(ctx, len); + if (!b) return JS_EXCEPTION; if (!target_is_regex) { - if (!JS_VALUE_IS_TEXT (argv[1])) - return JS_ThrowInternalError ( + if (!JS_VALUE_IS_TEXT(argv[1])) + return JS_ThrowInternalError( ctx, "Second arg of replace must be pattern or text."); - JSText *tp = JS_VALUE_GET_STRING (argv[1]); - int t_len = (int)tp->len; + JSText *tp = JS_VALUE_GET_STRING(argv[1]); + int t_len = (int)JSText_len(tp); if (t_len == 0) { int32_t count = 0; @@ -22800,28 +22798,29 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, if (limit >= 0 && count >= limit) break; JSValue match = JS_KEY_empty; - if (JS_IsException (match)) goto fail_str_target; + if (JS_IsException(match)) goto fail_str_target; - JSValue rep = make_replacement (ctx, argc, argv, boundary, match); - if (JS_IsException (rep)) goto fail_str_target; + JSValue rep = make_replacement(ctx, argc, argv, boundary, match); + if (JS_IsException(rep)) goto fail_str_target; count++; - if (!JS_IsNull (rep)) { - if (sb_concat_value_to_string_free (ctx, b, rep) < 0) - goto fail_str_target; + if (!JS_IsNull(rep)) { + b = pt_concat_value_to_string_free(ctx, b, rep); + if (!b) goto fail_str_target; } else { - JS_FreeValue (ctx, rep); + JS_FreeValue(ctx, rep); } if (boundary < len) { - JSValue ch = js_sub_string (ctx, sp, boundary, boundary + 1); - if (JS_IsException (ch)) goto fail_str_target; - if (string_buffer_concat_value_free (b, ch)) goto fail_str_target; + JSValue ch = js_sub_string(ctx, sp, boundary, boundary + 1); + if (JS_IsException(ch)) goto fail_str_target; + b = pretext_concat_value_free(ctx, b, ch); + if (!b) goto fail_str_target; } } - return string_buffer_end (b); + return pretext_end(ctx, b); } int pos = 0; @@ -22831,7 +22830,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int found = -1; for (int i = pos; i <= len - t_len; i++) { - if (!string_cmp (sp, tp, i, 0, t_len)) { + if (!string_cmp(sp, tp, i, 0, t_len)) { found = i; break; } @@ -22839,131 +22838,135 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, if (found < 0) break; if (found > pos) { - JSValue sub = js_sub_string (ctx, sp, pos, found); - if (JS_IsException (sub)) goto fail_str_target; - if (string_buffer_concat_value_free (b, sub)) goto fail_str_target; + JSValue sub = js_sub_string(ctx, sp, pos, found); + if (JS_IsException(sub)) goto fail_str_target; + b = pretext_concat_value_free(ctx, b, sub); + if (!b) goto fail_str_target; } - JSValue match = js_sub_string (ctx, sp, found, found + t_len); - if (JS_IsException (match)) goto fail_str_target; + JSValue match = js_sub_string(ctx, sp, found, found + t_len); + if (JS_IsException(match)) goto fail_str_target; - JSValue rep = make_replacement (ctx, argc, argv, found, match); - if (JS_IsException (rep)) goto fail_str_target; + JSValue rep = make_replacement(ctx, argc, argv, found, match); + if (JS_IsException(rep)) goto fail_str_target; count++; - if (!JS_IsNull (rep)) { - if (sb_concat_value_to_string_free (ctx, b, rep) < 0) - goto fail_str_target; + if (!JS_IsNull(rep)) { + b = pt_concat_value_to_string_free(ctx, b, rep); + if (!b) goto fail_str_target; } else { - JS_FreeValue (ctx, rep); + JS_FreeValue(ctx, rep); } pos = found + t_len; } if (pos < len) { - JSValue sub = js_sub_string (ctx, sp, pos, len); - if (JS_IsException (sub)) goto fail_str_target; - if (string_buffer_concat_value_free (b, sub)) goto fail_str_target; + JSValue sub = js_sub_string(ctx, sp, pos, len); + if (JS_IsException(sub)) goto fail_str_target; + b = pretext_concat_value_free(ctx, b, sub); + if (!b) goto fail_str_target; } - return string_buffer_end (b); + return pretext_end(ctx, b); fail_str_target: - string_buffer_free (b); + pretext_free(ctx, b); return JS_EXCEPTION; } /* Regex target */ JSValue rx = argv[1]; - JSValue orig_last_index = JS_GetPropertyStr (ctx, rx, "lastIndex"); - if (JS_IsException (orig_last_index)) goto fail_rx; + JSValue orig_last_index = JS_GetPropertyStr(ctx, rx, "lastIndex"); + if (JS_IsException(orig_last_index)) goto fail_rx; int have_orig_last_index = 1; int pos = 0; int32_t count = 0; while (pos <= len && (limit < 0 || count < limit)) { - if (JS_SetPropertyStr (ctx, rx, "lastIndex", JS_NewInt32 (ctx, 0)) < 0) + if (JS_SetPropertyStr(ctx, rx, "lastIndex", JS_NewInt32(ctx, 0)) < 0) goto fail_rx; - JSValue sub_str = js_sub_string (ctx, sp, pos, len); - if (JS_IsException (sub_str)) goto fail_rx; + JSValue sub_str = js_sub_string(ctx, sp, pos, len); + if (JS_IsException(sub_str)) goto fail_rx; JSValue exec_res - = JS_Invoke (ctx, rx, JS_KEY_exec, 1, (JSValue *)&sub_str); - JS_FreeValue (ctx, sub_str); - if (JS_IsException (exec_res)) goto fail_rx; + = JS_Invoke(ctx, rx, JS_KEY_exec, 1, (JSValue *)&sub_str); + JS_FreeValue(ctx, sub_str); + if (JS_IsException(exec_res)) goto fail_rx; - if (JS_IsNull (exec_res)) { - JS_FreeValue (ctx, exec_res); + if (JS_IsNull(exec_res)) { + JS_FreeValue(ctx, exec_res); break; } - JSValue idx_val = JS_GetPropertyStr (ctx, exec_res, "index"); - if (JS_IsException (idx_val)) { - JS_FreeValue (ctx, exec_res); + JSValue idx_val = JS_GetPropertyStr(ctx, exec_res, "index"); + if (JS_IsException(idx_val)) { + JS_FreeValue(ctx, exec_res); goto fail_rx; } int32_t local_index = 0; - if (JS_ToInt32 (ctx, &local_index, idx_val)) { - JS_FreeValue (ctx, idx_val); - JS_FreeValue (ctx, exec_res); + if (JS_ToInt32(ctx, &local_index, idx_val)) { + JS_FreeValue(ctx, idx_val); + JS_FreeValue(ctx, exec_res); goto fail_rx; } - JS_FreeValue (ctx, idx_val); + JS_FreeValue(ctx, idx_val); if (local_index < 0) local_index = 0; int found = pos + local_index; if (found < pos) found = pos; if (found > len) { - JS_FreeValue (ctx, exec_res); + JS_FreeValue(ctx, exec_res); break; } - JSValue match = JS_GetPropertyStr (ctx, exec_res, "match"); - if (JS_IsException (match)) { - JS_FreeValue (ctx, exec_res); + JSValue match = JS_GetPropertyStr(ctx, exec_res, "match"); + if (JS_IsException(match)) { + JS_FreeValue(ctx, exec_res); goto fail_rx; } - JSValue end_val = JS_GetPropertyStr (ctx, exec_res, "end"); - if (JS_IsException (end_val)) { - JS_FreeValue (ctx, match); - JS_FreeValue (ctx, exec_res); + JSValue end_val = JS_GetPropertyStr(ctx, exec_res, "end"); + if (JS_IsException(end_val)) { + JS_FreeValue(ctx, match); + JS_FreeValue(ctx, exec_res); goto fail_rx; } int32_t end = 0; - if (JS_ToInt32 (ctx, &end, end_val)) { - JS_FreeValue (ctx, end_val); - JS_FreeValue (ctx, match); - JS_FreeValue (ctx, exec_res); + if (JS_ToInt32(ctx, &end, end_val)) { + JS_FreeValue(ctx, end_val); + JS_FreeValue(ctx, match); + JS_FreeValue(ctx, exec_res); goto fail_rx; } - JS_FreeValue (ctx, end_val); - JS_FreeValue (ctx, exec_res); + JS_FreeValue(ctx, end_val); + JS_FreeValue(ctx, exec_res); int match_len = end - local_index; if (match_len < 0) match_len = 0; if (found > pos) { - JSValue prefix = js_sub_string (ctx, sp, pos, found); - if (JS_IsException (prefix)) goto fail_rx; - if (string_buffer_concat_value_free (b, prefix)) goto fail_rx; + JSValue prefix = js_sub_string(ctx, sp, pos, found); + if (JS_IsException(prefix)) goto fail_rx; + b = pretext_concat_value_free(ctx, b, prefix); + if (!b) goto fail_rx; } - JSValue rep = make_replacement (ctx, argc, argv, found, match); - if (JS_IsException (rep)) goto fail_rx; + JSValue rep = make_replacement(ctx, argc, argv, found, match); + if (JS_IsException(rep)) goto fail_rx; count++; - if (!JS_IsNull (rep)) { - if (sb_concat_value_to_string_free (ctx, b, rep) < 0) goto fail_rx; + if (!JS_IsNull(rep)) { + b = pt_concat_value_to_string_free(ctx, b, rep); + if (!b) goto fail_rx; } else { - JS_FreeValue (ctx, rep); + JS_FreeValue(ctx, rep); } pos = found + match_len; @@ -22976,21 +22979,23 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, } if (pos < len) { - JSValue tail = js_sub_string (ctx, sp, pos, len); - if (JS_IsException (tail)) goto fail_rx; - if (string_buffer_concat_value_free (b, tail)) goto fail_rx; + JSValue tail = js_sub_string(ctx, sp, pos, len); + if (JS_IsException(tail)) goto fail_rx; + b = pretext_concat_value_free(ctx, b, tail); + if (!b) goto fail_rx; } if (have_orig_last_index) - JS_SetPropertyStr (ctx, rx, "lastIndex", orig_last_index); + JS_SetPropertyStr(ctx, rx, "lastIndex", orig_last_index); - return string_buffer_end (b); + return pretext_end(ctx, b); fail_rx: - if (!JS_IsNull (orig_last_index) && !JS_IsException (orig_last_index)) { - JS_SetPropertyStr (ctx, rx, "lastIndex", orig_last_index); + pretext_free(ctx, b); + if (!JS_IsNull(orig_last_index) && !JS_IsException(orig_last_index)) { + JS_SetPropertyStr(ctx, rx, "lastIndex", orig_last_index); } else { - JS_FreeValue (ctx, orig_last_index); + JS_FreeValue(ctx, orig_last_index); } return JS_EXCEPTION; } @@ -23017,7 +23022,7 @@ static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc, if (JS_IsException (str)) return str; JSText *p = JS_VALUE_GET_STRING (str); - int len = (int)p->len; + int len = (int)JSText_len(p); int from = 0; if (argc > 2 && !JS_IsNull (argv[2])) { @@ -23041,7 +23046,7 @@ static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc, } JSText *t = JS_VALUE_GET_STRING (target); - int t_len = (int)t->len; + int t_len = (int)JSText_len(t); int result = -1; if (len >= t_len) { @@ -23125,8 +23130,8 @@ static inline uint32_t js_str_get (JSText *s, int idx) { static int js_str_find_range (JSText *hay, int from, int to, JSText *needle) { - int nlen = (int)needle->len; - int hlen = (int)hay->len; + int nlen = (int)JSText_len(needle); + int hlen = (int)JSText_len(hay); if (from < 0) from = 0; if (to < 0) to = 0; @@ -23163,7 +23168,7 @@ static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, if (JS_IsException (str)) return JS_EXCEPTION; JSText *p = JS_VALUE_GET_STRING (str); - int len = (int)p->len; + int len = (int)JSText_len(p); int from = 0; if (argc >= 3 && !JS_IsNull (argv[2])) { @@ -23279,7 +23284,7 @@ static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, if (JS_IsException (needle_val)) return JS_EXCEPTION; JSText *needle = JS_VALUE_GET_STRING (needle_val); - int needle_len = (int)needle->len; + int needle_len = (int)JSText_len(needle); int pos = js_str_find_range (p, from, to, needle); JS_FreeValue (ctx, needle_val); @@ -23529,7 +23534,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, /* array(text, length) - dice into chunks */ if (JS_VALUE_IS_TEXT (arg)) { JSText *p = JS_VALUE_GET_STRING (arg); - int len = p->len; + int len = (int)JSText_len(p); if (argc < 2 || JS_IsNull (argv[1])) { /* Split into characters */ @@ -25416,7 +25421,7 @@ static JSValue js_cell_length (JSContext *ctx, JSValue this_val, int argc, /* Strings return codepoint count */ if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) { JSText *p = JS_VALUE_GET_STRING (val); - return JS_NewInt32 (ctx, p->len); + return JS_NewInt32 (ctx, (int)JSText_len(p)); } /* Check for blob */ diff --git a/source/quickjs.h b/source/quickjs.h index 9278d24b..b2d9fdb9 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -150,9 +150,7 @@ enum { JS_TAG_CATCH_OFFSET = 0x1F, /* 11111 */ }; -typedef struct JSRefCountHeader { - int ref_count; -} JSRefCountHeader; +#define JS_EMPTY_TEXT ((JSValue)JS_TAG_STRING_IMM) /* JSGCRef - for rooting values during GC */ typedef struct JSGCRef { @@ -601,7 +599,7 @@ static inline JS_BOOL JS_IsBlob (JSValue v) { } static inline JS_BOOL JS_IsText(JSValue v) { - return JS_IsObject(v) && objhdr_type(*(objhdr_t *)JS_VALUE_GET_PTR(v)) == OBJ_TEXT; + return MIST_IsImmediateASCII(v) || (JS_IsObject(v) && objhdr_type(*(objhdr_t *)JS_VALUE_GET_PTR(v)) == OBJ_TEXT); } // Fundamental