diff --git a/include/utf8.h b/include/utf8.h index 6fdcea4..48a573c 100644 --- a/include/utf8.h +++ b/include/utf8.h @@ -20,6 +20,7 @@ utf8proc_ssize_t utf8_whatwg_decode( size_t utf8_strlen(const char *str, size_t byte_len); size_t utf16_strlen(const char *str, size_t byte_len); +size_t byte_offset_to_utf16(const char *str, size_t byte_off); size_t utf8_char_len_at(const char *str, size_t byte_len, size_t pos); char *utf8_json_quote(const char *str, size_t byte_len, size_t *out_len); diff --git a/src/ant.c b/src/ant.c index f30f04b..611382c 100644 --- a/src/ant.c +++ b/src/ant.c @@ -8246,23 +8246,32 @@ static ant_value_t builtin_string_indexOf(ant_t *js, ant_value_t *args, int narg ant_offset_t str_len, str_off = vstr(js, str, &str_len); ant_offset_t search_len, search_off = vstr(js, search, &search_len); - ant_offset_t start = 0; - double dstr_len = D(str_len); + const char *str_ptr = (char *)(uintptr_t)(str_off); + const char *search_ptr = (char *)(uintptr_t)(search_off); + size_t utf16_len = utf16_strlen(str_ptr, str_len); + + ant_offset_t start_utf16 = 0; if (nargs >= 2 && vtype(args[1]) == T_NUM) { double pos = tod(args[1]); if (pos < 0) pos = 0; - if (pos > dstr_len) pos = dstr_len; - start = (ant_offset_t) pos; + if (pos > D(utf16_len)) pos = D(utf16_len); + start_utf16 = (ant_offset_t) pos; } - if (search_len == 0) return tov(D(start)); - if (start + search_len > str_len) return tov(-1); + if (search_len == 0) return tov(D(start_utf16)); - const char *str_ptr = (char *)(uintptr_t)(str_off); - const char *search_ptr = (char *)(uintptr_t)(search_off); + size_t byte_start = 0; + if (start_utf16 > 0) { + int off = utf16_index_to_byte_offset(str_ptr, str_len, start_utf16, NULL); + if (off < 0) return tov(-1); + byte_start = (size_t)off; + } - for (ant_offset_t i = start; i <= str_len - search_len; i++) { - if (memcmp(str_ptr + i, search_ptr, search_len) == 0) return tov(D(i)); + if (byte_start + search_len > (size_t)str_len) return tov(-1); + + for (size_t i = byte_start; i <= (size_t)str_len - search_len; i++) { + if (memcmp(str_ptr + i, search_ptr, search_len) == 0) + return tov(D(byte_offset_to_utf16(str_ptr, i))); } return tov(-1); } diff --git a/src/silver/compiler.c b/src/silver/compiler.c index 0545163..616e8a1 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -12,6 +12,7 @@ #include #include + enum { SV_ITER_HINT_GENERIC = 0, SV_ITER_HINT_ARRAY = 1, @@ -122,6 +123,7 @@ typedef struct sv_compiler { int deferred_export_cap; struct const_dedup_entry *const_dedup; + struct sv_line_table *line_table; } sv_compiler_t; typedef struct const_dedup_entry { @@ -131,6 +133,50 @@ typedef struct const_dedup_entry { UT_hash_handle hh; } const_dedup_entry_t; +typedef struct sv_line_table { + uint32_t *offsets; + int count; +} sv_line_table_t; + +static sv_line_table_t *build_line_table(const char *source, ant_offset_t source_len) { + if (!source || source_len <= 0) return NULL; + sv_line_table_t *lt = malloc(sizeof(sv_line_table_t)); + if (!lt) return NULL; + + int cap = (int)(source_len / 32) + 64; + lt->offsets = malloc((size_t)cap * sizeof(uint32_t)); + lt->count = 0; + lt->offsets[lt->count++] = 0; + + for (ant_offset_t i = 0; i < source_len; i++) { + if (source[i] == '\n') { + if (lt->count >= cap) { + cap *= 2; + lt->offsets = realloc(lt->offsets, (size_t)cap * sizeof(uint32_t)); + } + lt->offsets[lt->count++] = (uint32_t)(i + 1); + } + } + return lt; +} + +static void free_line_table(sv_line_table_t *lt) { + if (!lt) return; + free(lt->offsets); + free(lt); +} + +static void line_table_lookup(sv_line_table_t *lt, uint32_t off, uint32_t *out_line, uint32_t *out_col) { + int lo = 0, hi = lt->count - 1; + while (lo < hi) { + int mid = lo + (hi - lo + 1) / 2; + if (lt->offsets[mid] <= off) lo = mid; + else hi = mid - 1; + } + *out_line = (uint32_t)(lo + 1); + *out_col = off - lt->offsets[lo] + 1; +} + static sv_func_t *compile_function_body( sv_compiler_t *enclosing, sv_ast_t *node, sv_compile_mode_t mode @@ -231,7 +277,9 @@ static void emit_srcpos(sv_compiler_t *c, sv_ast_t *node) { if (c->srcpos_count > 0 && c->last_srcpos_off == off && c->last_srcpos_end == end) return; uint32_t line, col; - if (c->srcpos_count > 0 && off >= c->last_srcpos_off) { + if (c->line_table) { + line_table_lookup(c->line_table, off, &line, &col); + } else if (c->srcpos_count > 0 && off >= c->last_srcpos_off) { line = c->srcpos[c->srcpos_count - 1].line; col = c->srcpos[c->srcpos_count - 1].col; for (uint32_t i = c->last_srcpos_off; i < off; i++) { @@ -4075,6 +4123,7 @@ static sv_func_t *compile_function_body( comp.filename = enclosing->filename; comp.source = enclosing->source; comp.source_len = enclosing->source_len; + comp.line_table = enclosing->line_table; comp.enclosing = enclosing; comp.scope_depth = 0; comp.is_arrow = !!(node->flags & FN_ARROW); @@ -4724,7 +4773,9 @@ sv_func_t *sv_compile(ant_t *js, sv_ast_t *program, sv_compile_mode_t mode, cons root.mode = mode; root.is_strict = ((program->flags & FN_PARSE_STRICT) != 0); + root.line_table = build_line_table(root.source, source_len); sv_func_t *func = compile_function_body(&root, &top_fn, mode); + free_line_table(root.line_table); if (js->thrown_exists || !func) return NULL; return func; } diff --git a/src/utf8.c b/src/utf8.c index b83593c..2216187 100644 --- a/src/utf8.c +++ b/src/utf8.c @@ -236,6 +236,23 @@ int utf16_range_to_byte_range( return 0; } +size_t byte_offset_to_utf16(const char *str, size_t byte_off) { + const unsigned char *p = (const unsigned char *)str; + const unsigned char *end = p + byte_off; + size_t utf16_pos = 0; + + while (p < end) { + unsigned char c = *p; + if (c < 0x80) { p++; utf16_pos++; } + else if ((c & 0xE0) == 0xC0) { p += 2; utf16_pos++; } + else if ((c & 0xF0) == 0xE0) { p += 3; utf16_pos++; } + else if ((c & 0xF8) == 0xF0) { p += 4; utf16_pos += 2; } + else { p++; utf16_pos++; } + if (p > end) p = end; + } + return utf16_pos; +} + uint32_t utf16_code_unit_at(const char *str, size_t byte_len, size_t utf16_idx) { const unsigned char *p = (const unsigned char *)str; const unsigned char *end = p + byte_len;