From 7e88de4e288df125dce38b88b8d9de7eeaff1316 Mon Sep 17 00:00:00 2001 From: x Date: Sun, 11 Oct 2026 02:39:19 -0500 Subject: [PATCH] Buffer and host builtins onto the slot API (#1665 arm D B6) Batch B6 of the arm D step-2 design: builtins_buf.c and builtins_host.c leave the legacy borrow API and join the migrated-files gate (Codex Cloud builder). strict_shape_contract.py's candidate discovery also matches list_sort( (widens the audited population; it is unchanged at 190). Local gates on top of B5: Ir vs B5 flat; tape identical; jit-smoke; jit_diff (257); release 4220/4221, full ASan (detect_leaks=1) 4211/4212 with leak tally 0 -- the one failure in each is the pre-existing [99d] (#1708); rehearsal adds the pre-existing [70d] (#1709). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1665-arm-d-b6.md | 1 + src/builtins_buf.c | 172 ++++++++++++++++------------- src/builtins_host.c | 116 +++++++++++-------- tools/container_migrated_files.txt | 2 + tools/strict_shape_contract.py | 2 +- tools/strict_shape_contracts.json | 30 ++--- 6 files changed, 182 insertions(+), 141 deletions(-) create mode 100644 changes/internal/1665-arm-d-b6.md diff --git a/changes/internal/1665-arm-d-b6.md b/changes/internal/1665-arm-d-b6.md new file mode 100644 index 00000000..ac0632bd --- /dev/null +++ b/changes/internal/1665-arm-d-b6.md @@ -0,0 +1 @@ +- Migrate buffer and host builtins to the container slot API. diff --git a/src/builtins_buf.c b/src/builtins_buf.c index b6dd34ac..61b82df8 100644 --- a/src/builtins_buf.c +++ b/src/builtins_buf.c @@ -32,8 +32,8 @@ Value* builtin_buffer(Value *arg) { /* buffer of [rows, cols] -> shaped 2-D buffer (flat double[rows*cols]) */ if (arg && arg->type == VAL_LIST && arg->data.list.count == 2 && - list_get_borrow(arg, 0)->type == VAL_NUM && - list_get_borrow(arg, 1)->type == VAL_NUM) { + list_elem_type(arg, 0) == VAL_NUM && + list_elem_type(arg, 1) == VAL_NUM) { int r = (int)eigs_list_num(arg, 0, __func__); int c = (int)eigs_list_num(arg, 1, __func__); if (r < 0) r = 0; @@ -71,11 +71,12 @@ Value* builtin_buffer(Value *arg) { Value* builtin_reshape(Value *arg) { STRICT_LIST_MAX(arg, 3, "reshape"); if (!arg || arg->type != VAL_LIST || arg->data.list.count < 3) return make_null(); - Value *b = list_get_borrow(arg, 0); + EIGS_VIEW(b_view); + Value *b = list_get_view(arg, 0, &b_view); if (b->type != VAL_BUFFER) return make_null(); BOOL_REFUSE(arg, "reshape"); /* rows/cols; the buffer is not a bool */ - if (list_get_borrow(arg, 1)->type != VAL_NUM || - list_get_borrow(arg, 2)->type != VAL_NUM) return make_null(); + if (list_elem_type(arg, 1) != VAL_NUM || + list_elem_type(arg, 2) != VAL_NUM) return make_null(); int r = (int)eigs_list_num(arg, 1, __func__); int c = (int)eigs_list_num(arg, 2, __func__); if (r < 0 || c < 0 || (long)r * (long)c != (long)b->data.buffer.count) return make_null(); @@ -103,7 +104,8 @@ Value* builtin_buf_get(Value *arg) { /* fs:CHANNEL the rt_error above already raised */ return make_num(0); } - Value *buf = list_get_borrow(arg, 0); + EIGS_VIEW(buf_view); + Value *buf = list_get_view(arg, 0, &buf_view); if (!buf || buf->type != VAL_BUFFER) { rt_error(EK_TYPE, 0, "buf_get: first argument must be a buffer"); /* fs:CHANNEL the rt_error above already raised */ @@ -127,7 +129,8 @@ Value* builtin_buf_set(Value *arg) { rt_error(EK_TYPE, 0, "buf_set requires [buffer, index, value]"); return make_null(); } - Value *buf = list_get_borrow(arg, 0); + EIGS_VIEW(buf_view); + Value *buf = list_get_view(arg, 0, &buf_view); if (!buf || buf->type != VAL_BUFFER) { rt_error(EK_TYPE, 0, "buf_set: first argument must be a buffer"); return make_null(); @@ -135,12 +138,12 @@ Value* builtin_buf_set(Value *arg) { /* #1061: both operands were read through the num union member unchecked * -- a string index or value read garbage bits (the #1007 type-pun class). * Loud, like the `b[i] is v` opcode path. */ - if (list_get_borrow(arg, 1)->type != VAL_NUM) { - rt_error(EK_TYPE, 0, "buf_set: index must be a number, got %s", val_type_name(list_get_borrow(arg, 1)->type)); + if (list_elem_type(arg, 1) != VAL_NUM) { + rt_error(EK_TYPE, 0, "buf_set: index must be a number, got %s", val_type_name(list_elem_type(arg, 1))); return make_null(); } - if (list_get_borrow(arg, 2)->type != VAL_NUM) { - rt_error(EK_TYPE, 0, "cannot store %s in a buffer (buffers hold numbers)", val_type_name(list_get_borrow(arg, 2)->type)); + if (list_elem_type(arg, 2) != VAL_NUM) { + rt_error(EK_TYPE, 0, "cannot store %s in a buffer (buffers hold numbers)", val_type_name(list_elem_type(arg, 2))); return make_null(); } int idx = (int)eigs_list_num(arg, 1, __func__); @@ -178,11 +181,11 @@ Value* builtin_buf_from_list(Value *arg) { v->data.buffer.data = xcalloc(n > 0 ? n : 1, sizeof(double)); v->refcount = 1; for (int i = 0; i < n; i++) { - if (list_get_borrow(arg, i)->type == VAL_NUM) { - v->data.buffer.data[i] = eigs_num_arg(list_get_borrow(arg, i), __func__); + if (list_elem_type(arg, i) == VAL_NUM) { + v->data.buffer.data[i] = eigs_slot_num(list_slot(arg, i), __func__); } else { /* #1061: a non-number element silently stayed 0.0. */ - const char *tn = val_type_name(list_get_borrow(arg, i)->type); + const char *tn = val_type_name(list_elem_type(arg, i)); val_decref(v); rt_error(EK_TYPE, 0, "buf_from_list: element %d is %s (buffers hold numbers)", i, tn); return make_null(); @@ -197,7 +200,8 @@ Value* builtin_buf_from_list(Value *arg) { static int strict_numeric_byte_list(Value *arg, const char *who, int nul_ends) { if (!arg || arg->type != VAL_LIST) return 1; for (int i = 0; i < arg->data.list.count; i++) { - Value *item = list_get_borrow(arg, i); + EIGS_VIEW(item_view); + Value *item = list_get_view(arg, i, &item_view); /* #1637: a bool byte is refused in every strict mode. */ if (!item || (item->type != VAL_NUM && (g_strict || item->type == VAL_BOOL))) { rt_error(EK_TYPE, 0, "%s: expected numeric byte values", who); @@ -220,10 +224,8 @@ static int strict_numeric_byte_list(Value *arg, const char *who, int nul_ends) { * Surfaced by tidelog's CBOR text-string decoder. */ Value* builtin_str_from_bytes(Value *arg) { int n = 0; - Value **items = NULL; if (arg && arg->type == VAL_LIST) { n = arg->data.list.count; - items = list_values_storage(arg); } else if (arg && arg->type == VAL_BUFFER) { n = arg->data.buffer.count; } else { @@ -233,8 +235,9 @@ Value* builtin_str_from_bytes(Value *arg) { char *s = xcalloc((size_t)(n > 0 ? n : 0) + 1, 1); int len = 0; for (int i = 0; i < n; i++) { - double dv = items ? (items[i] && items[i]->type == VAL_NUM ? eigs_num_arg(items[i], __func__) : 0.0) - : buffer_read_num(arg, i); + double dv = arg->type == VAL_LIST + ? (list_elem_type(arg, i) == VAL_NUM ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) + : buffer_read_num(arg, i); if (g_has_error) { free(s); return make_null(); } int b = finite_num_to_byte(dv); if (b == 0) break; /* C-string terminates at NUL */ @@ -273,8 +276,8 @@ Value* builtin_f64_from_bytes(Value *arg) { if (arg && arg->type == VAL_LIST) { int n = arg->data.list.count; for (int i = 0; i < 8 && i < n; i++) - if (list_get_borrow(arg, i) && list_get_borrow(arg, i)->type == VAL_NUM) - bytes_in[i] = eigs_num_arg(list_get_borrow(arg, i), __func__); + if (list_elem_type(arg, i) == VAL_NUM) + bytes_in[i] = eigs_slot_num(list_slot(arg, i), __func__); } else if (arg && arg->type == VAL_BUFFER) { int n = arg->data.buffer.count; for (int i = 0; i < 8 && i < n; i++) { @@ -330,10 +333,8 @@ static int zlib_bytes_arg(Value *arg, const char *who, *out = NULL; *out_n = 0; int n = 0; - Value **items = NULL; if (arg && arg->type == VAL_LIST) { n = arg->data.list.count; - items = list_values_storage(arg); } else if (arg && arg->type == VAL_BUFFER) { n = arg->data.buffer.count; } else { @@ -345,8 +346,9 @@ static int zlib_bytes_arg(Value *arg, const char *who, if (!strict_numeric_byte_list(arg, who, 0)) return 0; unsigned char *b = xmalloc((size_t)(n > 0 ? n : 1)); for (int i = 0; i < n; i++) { - double dv = items ? (items[i] && items[i]->type == VAL_NUM ? eigs_num_arg(items[i], __func__) : 0.0) - : buffer_read_num(arg, i); + double dv = arg->type == VAL_LIST + ? (list_elem_type(arg, i) == VAL_NUM ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) + : buffer_read_num(arg, i); if (g_has_error) { free(b); return 0; } b[i] = finite_num_to_byte(dv); } @@ -487,12 +489,12 @@ Value* builtin_inflate(Value *arg) { (void)arg; return zlib_unavailable("in * bounds. Bounds failures RAISE (index_range / value), matching the * #490-#512 direction (buf_get/buf_set/set_at) — no silent truncation: * a clamped audio mix is a silently wrong render. */ -static int buf_count_arg(const char *who, Value *cnt_val, long long *out) { - if (!cnt_val || cnt_val->type != VAL_NUM) { +static int buf_count_arg(const char *who, EigsSlot cnt, long long *out) { + if (slot_type(cnt) != VAL_NUM) { rt_error(EK_VALUE, 0, "%s: count must be a number", who); return 0; } - long long c = (long long)eigs_num_arg(cnt_val, __func__); + long long c = (long long)eigs_slot_num(cnt, __func__); if (c < 0) { rt_error(EK_VALUE, 0, "%s: count must be non-negative (got %lld)", who, c); @@ -502,38 +504,38 @@ static int buf_count_arg(const char *who, Value *cnt_val, long long *out) { return 1; } -static int buf_num_arg(const char *who, const char *what, Value *v, +static int buf_num_arg(const char *who, const char *what, EigsSlot s, double *out) { - if (!v || v->type != VAL_NUM) { + if (slot_type(s) != VAL_NUM) { rt_error(EK_VALUE, 0, "%s: %s must be a number", who, what); return 0; } - *out = eigs_num_arg(v, __func__); + *out = eigs_slot_num(s, __func__); return 1; } /* Validate one (buffer, offset, count) window. On success writes the * offset and returns 1; on failure raises and returns 0. count must * already be validated non-negative (buf_count_arg). */ -static int buf_window_arg(const char *who, Value *buf, Value *off_val, +static int buf_window_arg(const char *who, Value *buf, EigsSlot off, long long count, long long *out_off) { if (!buf || buf->type != VAL_BUFFER) { rt_error(EK_TYPE, 0, "%s: expected a buffer", who); return 0; } - if (!off_val || off_val->type != VAL_NUM) { + if (slot_type(off) != VAL_NUM) { rt_error(EK_VALUE, 0, "%s: offset must be a number", who); return 0; } - long long off = (long long)eigs_num_arg(off_val, __func__); + long long offset = (long long)eigs_slot_num(off, __func__); long long n = buf->data.buffer.count; - if (off < 0 || off > n - count) { + if (offset < 0 || offset > n - count) { rt_error(EK_INDEX, 0, "%s: window [%lld, %lld) out of range (length %lld)", - who, off, off + count, n); + who, offset, offset + count, n); return 0; } - *out_off = off; + *out_off = offset; return 1; } @@ -547,12 +549,14 @@ Value* builtin_buf_copy(Value *arg) { rt_error(EK_TYPE, 0, "buf_copy requires [src, src_off, dst, dst_off, count]"); return make_null(); } - Value *src = list_get_borrow(arg, 0); - Value *dst = list_get_borrow(arg, 2); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 0, &src_view); + EIGS_VIEW(dst_view); + Value *dst = list_get_view(arg, 2, &dst_view); long long count, src_off, dst_off; - if (!buf_count_arg("buf_copy", list_get_borrow(arg, 4), &count) || - !buf_window_arg("buf_copy", src, list_get_borrow(arg, 1), count, &src_off) || - !buf_window_arg("buf_copy", dst, list_get_borrow(arg, 3), count, &dst_off)) + if (!buf_count_arg("buf_copy", list_slot(arg, 4), &count) || + !buf_window_arg("buf_copy", src, list_slot(arg, 1), count, &src_off) || + !buf_window_arg("buf_copy", dst, list_slot(arg, 3), count, &dst_off)) return make_null(); if (count == 0) return make_null(); memmove(&dst->data.buffer.data[dst_off], &src->data.buffer.data[src_off], @@ -574,14 +578,16 @@ Value* builtin_buf_mix(Value *arg) { rt_error(EK_TYPE, 0, "buf_mix requires [dst, src, dst_off, src_off, count, gain]"); return make_null(); } - Value *dst = list_get_borrow(arg, 0); - Value *src = list_get_borrow(arg, 1); + EIGS_VIEW(dst_view); + Value *dst = list_get_view(arg, 0, &dst_view); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 1, &src_view); long long count, dst_off, src_off; double gain; - if (!buf_count_arg("buf_mix", list_get_borrow(arg, 4), &count) || - !buf_window_arg("buf_mix", dst, list_get_borrow(arg, 2), count, &dst_off) || - !buf_window_arg("buf_mix", src, list_get_borrow(arg, 3), count, &src_off) || - !buf_num_arg("buf_mix", "gain", list_get_borrow(arg, 5), &gain)) + if (!buf_count_arg("buf_mix", list_slot(arg, 4), &count) || + !buf_window_arg("buf_mix", dst, list_slot(arg, 2), count, &dst_off) || + !buf_window_arg("buf_mix", src, list_slot(arg, 3), count, &src_off) || + !buf_num_arg("buf_mix", "gain", list_slot(arg, 5), &gain)) return make_null(); double *dd = &dst->data.buffer.data[dst_off]; double *sd = &src->data.buffer.data[src_off]; @@ -599,12 +605,13 @@ Value* builtin_buf_scale_range(Value *arg) { rt_error(EK_TYPE, 0, "buf_scale_range requires [buffer, off, count, gain]"); return make_null(); } - Value *buf = list_get_borrow(arg, 0); + EIGS_VIEW(buf_view); + Value *buf = list_get_view(arg, 0, &buf_view); long long count, off; double gain; - if (!buf_count_arg("buf_scale_range", list_get_borrow(arg, 2), &count) || - !buf_window_arg("buf_scale_range", buf, list_get_borrow(arg, 1), count, &off) || - !buf_num_arg("buf_scale_range", "gain", list_get_borrow(arg, 3), &gain)) + if (!buf_count_arg("buf_scale_range", list_slot(arg, 2), &count) || + !buf_window_arg("buf_scale_range", buf, list_slot(arg, 1), count, &off) || + !buf_num_arg("buf_scale_range", "gain", list_slot(arg, 3), &gain)) return make_null(); double *d = &buf->data.buffer.data[off]; for (long long i = 0; i < count; i++) @@ -621,12 +628,13 @@ Value* builtin_buf_fill(Value *arg) { rt_error(EK_TYPE, 0, "buf_fill requires [buffer, off, count, value]"); return make_null(); } - Value *buf = list_get_borrow(arg, 0); + EIGS_VIEW(buf_view); + Value *buf = list_get_view(arg, 0, &buf_view); long long count, off; double val; - if (!buf_count_arg("buf_fill", list_get_borrow(arg, 2), &count) || - !buf_window_arg("buf_fill", buf, list_get_borrow(arg, 1), count, &off) || - !buf_num_arg("buf_fill", "value", list_get_borrow(arg, 3), &val)) + if (!buf_count_arg("buf_fill", list_slot(arg, 2), &count) || + !buf_window_arg("buf_fill", buf, list_slot(arg, 1), count, &off) || + !buf_num_arg("buf_fill", "value", list_slot(arg, 3), &val)) return make_null(); double *d = &buf->data.buffer.data[off]; for (long long i = 0; i < count; i++) @@ -643,10 +651,11 @@ Value* builtin_buf_peak(Value *arg) { /* fs:CHANNEL the rt_error above already raised */ return make_num(0); } - Value *buf = list_get_borrow(arg, 0); + EIGS_VIEW(buf_view); + Value *buf = list_get_view(arg, 0, &buf_view); long long count, off; - if (!buf_count_arg("buf_peak", list_get_borrow(arg, 2), &count) || - !buf_window_arg("buf_peak", buf, list_get_borrow(arg, 1), count, &off)) + if (!buf_count_arg("buf_peak", list_slot(arg, 2), &count) || + !buf_window_arg("buf_peak", buf, list_slot(arg, 1), count, &off)) /* fs:CHANNEL buf_count_arg/buf_window_arg raise before returning 0 */ return make_num(0); double m = 0.0; @@ -672,12 +681,14 @@ Value* builtin_buf_dot(Value *arg) { /* fs:CHANNEL the rt_error above already raised */ return make_num(0); } - Value *a = list_get_borrow(arg, 0); - Value *b = list_get_borrow(arg, 1); + EIGS_VIEW(a_view); + Value *a = list_get_view(arg, 0, &a_view); + EIGS_VIEW(b_view); + Value *b = list_get_view(arg, 1, &b_view); long long count, a_off, b_off; - if (!buf_count_arg("buf_dot", list_get_borrow(arg, 4), &count) || - !buf_window_arg("buf_dot", a, list_get_borrow(arg, 2), count, &a_off) || - !buf_window_arg("buf_dot", b, list_get_borrow(arg, 3), count, &b_off)) + if (!buf_count_arg("buf_dot", list_slot(arg, 4), &count) || + !buf_window_arg("buf_dot", a, list_slot(arg, 2), count, &a_off) || + !buf_window_arg("buf_dot", b, list_slot(arg, 3), count, &b_off)) /* fs:CHANNEL buf_count_arg/buf_window_arg raise before returning 0 */ return make_num(0); double s = 0.0; @@ -724,15 +735,16 @@ Value* builtin_buf_from_pcm16le(Value *arg) { rt_error(EK_TYPE, 0, "buf_from_pcm16le requires [bytes, byte_off, count]"); return make_null(); } - Value *src = list_get_borrow(arg, 0); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 0, &src_view); long long count, off; - if (!buf_count_arg("buf_from_pcm16le", list_get_borrow(arg, 2), &count)) + if (!buf_count_arg("buf_from_pcm16le", list_slot(arg, 2), &count)) return make_null(); if (count > (long long)INT_MAX / 2) { /* 2*count below cannot overflow */ rt_error(EK_LIMIT, 0, "buf_from_pcm16le: count %lld over the buffer size limit", count); return make_null(); } - if (!buf_window_arg("buf_from_pcm16le", src, list_get_borrow(arg, 1), + if (!buf_window_arg("buf_from_pcm16le", src, list_slot(arg, 1), count * 2, &off)) return make_null(); Value *out = buf_alloc_flat(count); @@ -763,15 +775,16 @@ Value* builtin_buf_to_pcm16le(Value *arg) { rt_error(EK_TYPE, 0, "buf_to_pcm16le requires [floats, off, count]"); return make_null(); } - Value *src = list_get_borrow(arg, 0); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 0, &src_view); long long count, off; - if (!buf_count_arg("buf_to_pcm16le", list_get_borrow(arg, 2), &count)) + if (!buf_count_arg("buf_to_pcm16le", list_slot(arg, 2), &count)) return make_null(); if (count > (long long)INT_MAX / 2) { /* output is 2*count elements */ rt_error(EK_LIMIT, 0, "buf_to_pcm16le: count %lld over the buffer size limit", count); return make_null(); } - if (!buf_window_arg("buf_to_pcm16le", src, list_get_borrow(arg, 1), + if (!buf_window_arg("buf_to_pcm16le", src, list_slot(arg, 1), count, &off)) return make_null(); Value *out = buf_alloc_flat(count * 2); @@ -801,13 +814,16 @@ Value* builtin_buf_deinterleave(Value *arg) { rt_error(EK_TYPE, 0, "buf_deinterleave requires [src, channel, nch, count?]"); return make_null(); } - Value *src = list_get_borrow(arg, 0); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 0, &src_view); if (!src || src->type != VAL_BUFFER) { rt_error(EK_TYPE, 0, "buf_deinterleave: expected a buffer"); return make_null(); } - Value *ch_v = list_get_borrow(arg, 1); - Value *nch_v = list_get_borrow(arg, 2); + EIGS_VIEW(ch_v_view); + Value *ch_v = list_get_view(arg, 1, &ch_v_view); + EIGS_VIEW(nch_v_view); + Value *nch_v = list_get_view(arg, 2, &nch_v_view); if (!ch_v || ch_v->type != VAL_NUM || !nch_v || nch_v->type != VAL_NUM) { rt_error(EK_VALUE, 0, "buf_deinterleave: channel and nch must be numbers"); return make_null(); @@ -826,9 +842,8 @@ Value* builtin_buf_deinterleave(Value *arg) { long long n = src->data.buffer.count; long long avail = channel < n ? (n - channel + nch - 1) / nch : 0; long long count = avail; - if (arg->data.list.count >= 4 && list_get_borrow(arg, 3) && - list_get_borrow(arg, 3)->type != VAL_NULL) { - if (!buf_count_arg("buf_deinterleave", list_get_borrow(arg, 3), &count)) + if (arg->data.list.count >= 4 && list_elem_type(arg, 3) != VAL_NULL) { + if (!buf_count_arg("buf_deinterleave", list_slot(arg, 3), &count)) return make_null(); if (count > avail) { rt_error(EK_INDEX, 0, @@ -866,13 +881,14 @@ Value* builtin_buf_resample_linear(Value *arg) { rt_error(EK_TYPE, 0, "buf_resample_linear requires [src, dst_len]"); return make_null(); } - Value *src = list_get_borrow(arg, 0); + EIGS_VIEW(src_view); + Value *src = list_get_view(arg, 0, &src_view); if (!src || src->type != VAL_BUFFER) { rt_error(EK_TYPE, 0, "buf_resample_linear: expected a buffer"); return make_null(); } long long dst_len; - if (!buf_count_arg("buf_resample_linear", list_get_borrow(arg, 1), &dst_len)) + if (!buf_count_arg("buf_resample_linear", list_slot(arg, 1), &dst_len)) return make_null(); if (dst_len > (long long)INT_MAX) { rt_error(EK_LIMIT, 0, "buf_resample_linear: dst_len %lld over the buffer size limit", dst_len); diff --git a/src/builtins_host.c b/src/builtins_host.c index 13b9ada8..6b8a5e43 100644 --- a/src/builtins_host.c +++ b/src/builtins_host.c @@ -42,12 +42,12 @@ Value* builtin_match(Value *arg) { rt_error(EK_TYPE, 0, "regex_match requires [string, pattern]"); return make_list(0); } - if (list_get_borrow(arg, 0)->type != VAL_STR || list_get_borrow(arg, 1)->type != VAL_STR) { + if (list_elem_type(arg, 0) != VAL_STR || list_elem_type(arg, 1) != VAL_STR) { rt_error(EK_TYPE, 0, "regex_match: string and pattern must be strings"); return make_list(0); } - const char *str = list_get_borrow(arg, 0)->data.str; - const char *pattern = list_get_borrow(arg, 1)->data.str; + const char *str = list_get_ref(arg, 0)->data.str; + const char *pattern = list_get_ref(arg, 1)->data.str; regex_t re; /* #500: an invalid pattern used to return [] — indistinguishable from a @@ -100,12 +100,12 @@ Value* builtin_match_all(Value *arg) { rt_error(EK_TYPE, 0, "regex_find requires [string, pattern]"); return make_list(0); } - if (list_get_borrow(arg, 0)->type != VAL_STR || list_get_borrow(arg, 1)->type != VAL_STR) { + if (list_elem_type(arg, 0) != VAL_STR || list_elem_type(arg, 1) != VAL_STR) { rt_error(EK_TYPE, 0, "regex_find: string and pattern must be strings"); return make_list(0); } - const char *str = list_get_borrow(arg, 0)->data.str; - const char *pattern = list_get_borrow(arg, 1)->data.str; + const char *str = list_get_ref(arg, 0)->data.str; + const char *pattern = list_get_ref(arg, 1)->data.str; regex_t re; if (regcomp(&re, pattern, REG_EXTENDED) != 0) { /* #500 */ @@ -143,18 +143,18 @@ Value* builtin_regex_replace(Value *arg) { * discards it at the CHECK_ERROR seam. */ return make_str(""); } - if (list_get_borrow(arg, 0)->type != VAL_STR || - list_get_borrow(arg, 1)->type != VAL_STR || - list_get_borrow(arg, 2)->type != VAL_STR) { + if (list_elem_type(arg, 0) != VAL_STR || + list_elem_type(arg, 1) != VAL_STR || + list_elem_type(arg, 2) != VAL_STR) { rt_error(EK_TYPE, 0, "regex_replace: string, pattern and replacement must be strings"); /* fs:CHANNEL same as above — the unconditional rt_error is the error * channel; converting to ARG_GUARD would make this site quieter with * strict OFF, not louder. */ return make_str(""); } - const char *str = list_get_borrow(arg, 0)->data.str; - const char *pattern = list_get_borrow(arg, 1)->data.str; - const char *replacement = list_get_borrow(arg, 2)->data.str; + const char *str = list_get_ref(arg, 0)->data.str; + const char *pattern = list_get_ref(arg, 1)->data.str; + const char *replacement = list_get_ref(arg, 2)->data.str; regex_t re; /* #500: an invalid pattern used to return the input unchanged — a silent @@ -211,8 +211,10 @@ Value* builtin_stream_open(Value *arg) { STRICT_LIST_MAX(arg, 2, "stream_open"); ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "stream_open", "[path, count]", make_bool(0)); - Value *path_val = list_get_borrow(arg, 0); - Value *count_val = list_get_borrow(arg, 1); + EIGS_VIEW(path_val_view); + Value *path_val = list_get_view(arg, 0, &path_val_view); + EIGS_VIEW(count_val_view); + Value *count_val = list_get_view(arg, 1, &count_val_view); ARG_GUARD(!path_val || path_val->type != VAL_STR || !count_val || count_val->type != VAL_NUM, "stream_open", "[a string path, a number count]", make_bool(0)); if (eigs_num_arg(count_val, __func__) < 1 || @@ -331,8 +333,7 @@ Value* builtin_ls(Value *arg) { list_append_owned(list, make_str(entry->d_name)); } closedir(d); - qsort(list_values_storage(list), list->data.list.count, sizeof(Value*), - ls_entry_cmp); + list_sort(list, ls_entry_cmp); TRACE_NONDET_RECORD("ls", list); } @@ -397,10 +398,15 @@ Value* builtin_build_corpus(Value *arg) { if (!arg || arg->type != VAL_LIST || arg->data.list.count < 4) return make_null(); - Value *file_list = list_get_borrow(arg, 0); - Value *topn_val = list_get_borrow(arg, 1); - Value *stream_path_val = list_get_borrow(arg, 2); - Value *vocab_path_val = list_get_borrow(arg, 3); + EIGS_VIEW(file_list_view); + + Value *file_list = list_get_view(arg, 0, &file_list_view); + EIGS_VIEW(topn_val_view); + Value *topn_val = list_get_view(arg, 1, &topn_val_view); + EIGS_VIEW(stream_path_val_view); + Value *stream_path_val = list_get_view(arg, 2, &stream_path_val_view); + EIGS_VIEW(vocab_path_val_view); + Value *vocab_path_val = list_get_view(arg, 3, &vocab_path_val_view); if (!file_list || file_list->type != VAL_LIST) return make_null(); BOOL_REFUSE(topn_val, "build_corpus"); @@ -437,7 +443,8 @@ Value* builtin_build_corpus(Value *arg) { * been re-measured on the full corpus.) */ int slot_count = 0; if (arg->data.list.count >= 6) { - Value *sv = list_get_borrow(arg, 5); + EIGS_VIEW(sv_view); + Value *sv = list_get_view(arg, 5, &sv_view); double d = 0; if (eigs_opt_num(sv, &d, "build_corpus")) slot_count = (int)d; /* #1637: a bool raises */ if (g_has_error) return make_null(); @@ -465,7 +472,8 @@ Value* builtin_build_corpus(Value *arg) { * high-frequency collision is. Opt-in: 0 leaves the stream byte-identical. */ int int_count = 0; if (arg->data.list.count >= 7) { - Value *iv = list_get_borrow(arg, 6); + EIGS_VIEW(iv_view); + Value *iv = list_get_view(arg, 6, &iv_view); double d = 0; if (eigs_opt_num(iv, &d, "build_corpus")) int_count = (int)d; /* #1637: a bool raises */ if (g_has_error) return make_null(); @@ -487,7 +495,8 @@ Value* builtin_build_corpus(Value *arg) { int files_found = 0; for (int fi = 0; fi < n_files; fi++) { - Value *path_val = list_get_borrow(file_list, fi); + EIGS_VIEW(path_val_view); + Value *path_val = list_get_view(file_list, fi, &path_val_view); if (!path_val || path_val->type != VAL_STR) { file_tok_counts[fi] = 0; continue; } const char *path = path_val->data.str; @@ -643,7 +652,9 @@ Value* builtin_build_corpus(Value *arg) { for (int fi = 0; fi < n_files; fi++) { if (file_tok_counts[fi] <= 0) continue; - Value *path_val = list_get_borrow(file_list, fi); + EIGS_VIEW(path_val_view); + + Value *path_val = list_get_view(file_list, fi, &path_val_view); long fsize = 0; char *source = read_file_util(path_val->data.str, &fsize); if (!source) continue; @@ -752,7 +763,8 @@ Value* builtin_build_corpus(Value *arg) { * Sorted by count descending. Enables exact coverage(top_n) curves * without re-running the full corpus build. */ if (arg->data.list.count >= 5) { - Value *idents_path_val = list_get_borrow(arg, 4); + EIGS_VIEW(idents_path_val_view); + Value *idents_path_val = list_get_view(arg, 4, &idents_path_val_view); if (idents_path_val && idents_path_val->type == VAL_STR && n_idents > 0) { /* Build index array, sort descending by count via simple sort */ int *order = xmalloc_array(n_idents, sizeof(int)); @@ -1003,8 +1015,10 @@ Value* builtin_rename(Value *arg) { STRICT_LIST_MAX(arg, 2, "rename"); ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "rename", "[old_path, new_path]", make_bool(0)); - Value *from = list_get_borrow(arg, 0); - Value *to = list_get_borrow(arg, 1); + EIGS_VIEW(from_view); + Value *from = list_get_view(arg, 0, &from_view); + EIGS_VIEW(to_view); + Value *to = list_get_view(arg, 1, &to_view); ARG_GUARD(!from || from->type != VAL_STR || !to || to->type != VAL_STR, "rename", "two string paths", make_bool(0)); return make_bool(rename(from->data.str, to->data.str) == 0); @@ -1085,9 +1099,10 @@ Value* builtin_read_bytes_buf(Value *arg) { "read_bytes_buf of path, or read_bytes_buf of [path, max_bytes]"); return make_null(); } - path = list_get_borrow(arg, 0); + path = list_get_ref(arg, 0); if (arg->data.list.count >= 2) { - Value *mv = list_get_borrow(arg, 1); + EIGS_VIEW(mv_view); + Value *mv = list_get_view(arg, 1, &mv_view); if (!mv || mv->type != VAL_NUM) { rt_error(EK_VALUE, 0, "read_bytes_buf: max_bytes must be a number"); return make_null(); @@ -1212,8 +1227,10 @@ Value* builtin_write_text(Value *arg) { STRICT_LIST_MAX(arg, 2, "write_text"); ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "write_text", "[path, text]", make_bool(0)); - Value *path_val = list_get_borrow(arg, 0); - Value *text_val = list_get_borrow(arg, 1); + EIGS_VIEW(path_val_view); + Value *path_val = list_get_view(arg, 0, &path_val_view); + EIGS_VIEW(text_val_view); + Value *text_val = list_get_view(arg, 1, &text_val_view); ARG_GUARD(!path_val || path_val->type != VAL_STR || !text_val || text_val->type != VAL_STR, "write_text", "two strings", make_bool(0)); @@ -1270,9 +1287,9 @@ Value* builtin_exec_capture(Value *arg) { double timeout_sec = -1; Value *cmd_list = arg; if (arg->data.list.count == 2 - && list_get_borrow(arg, 0) && list_get_borrow(arg, 0)->type == VAL_LIST - && list_get_borrow(arg, 1) && list_get_borrow(arg, 1)->type == VAL_NUM) { - cmd_list = list_get_borrow(arg, 0); + && list_elem_type(arg, 0) == VAL_LIST + && list_elem_type(arg, 1) == VAL_NUM) { + cmd_list = list_get_ref(arg, 0); timeout_sec = eigs_list_num(arg, 1, __func__); ARG_GUARD(cmd_list->data.list.count < 1, "exec_capture", "a non-empty command list", exec_capture_result(-1, "")); @@ -1286,7 +1303,8 @@ Value* builtin_exec_capture(Value *arg) { * outcome, not an argument the caller got wrong. */ if (!argv) return exec_capture_result(-1, ""); for (int i = 0; i < total; i++) { - Value *v = list_get_borrow(cmd_list, i); + EIGS_VIEW(v_view); + Value *v = list_get_view(cmd_list, i, &v_view); if (!v || v->type != VAL_STR) { free(argv); ARG_GUARD(1, "exec_capture", "a list of strings", exec_capture_result(-1, "")); @@ -1417,8 +1435,10 @@ Value* builtin_proc_read_buf(Value *arg) { if (replay_blocks("proc_read_buf")) return make_null(); if (!arg || arg->type != VAL_LIST || arg->data.list.count != 2) return make_null(); - Value *fd_v = list_get_borrow(arg, 0); - Value *max_v = list_get_borrow(arg, 1); + EIGS_VIEW(fd_v_view); + Value *fd_v = list_get_view(arg, 0, &fd_v_view); + EIGS_VIEW(max_v_view); + Value *max_v = list_get_view(arg, 1, &max_v_view); if (!fd_v || fd_v->type != VAL_NUM || !max_v || max_v->type != VAL_NUM) return make_null(); int fd = (int)eigs_num_arg(fd_v, __func__); @@ -1481,25 +1501,26 @@ Value* builtin_write_bytes(Value *arg) { STRICT_LIST_MAX(arg, 3, "write_bytes"); ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "write_bytes", "[path, data] (optionally [path, data, append])", make_num(0)); - Value *path_val = list_get_borrow(arg, 0); - Value *data = list_get_borrow(arg, 1); + EIGS_VIEW(path_val_view); + Value *path_val = list_get_view(arg, 0, &path_val_view); + EIGS_VIEW(data_view); + Value *data = list_get_view(arg, 1, &data_view); ARG_GUARD(!path_val || path_val->type != VAL_STR, "write_bytes", "a string path as its first argument", make_num(0)); /* #1637: append is a flag -- a bool, or the older nonzero number. Any * other value raises rather than silently meaning "truncate". */ int append = 0; - if (arg->data.list.count >= 3 && list_get_borrow(arg, 2)) { - Value *fl = list_get_borrow(arg, 2); + if (arg->data.list.count >= 3) { + EIGS_VIEW(fl_view); + Value *fl = list_get_view(arg, 2, &fl_view); if (fl->type == VAL_BOOL) append = fl->data.boolean; else if (fl->type != VAL_NULL) append = (eigs_num_arg(fl, "write_bytes") != 0.0); if (g_has_error) return make_num(0); } int n = 0; - Value **items = NULL; if (data && data->type == VAL_LIST) { n = data->data.list.count; - items = list_values_storage(data); } else if (data && data->type == VAL_BUFFER) { n = data->data.buffer.count; } else { @@ -1517,14 +1538,15 @@ Value* builtin_write_bytes(Value *arg) { * two zero bytes and reported success. Same class as join/str_replace * — no stand-in return, so invisible to the classifier. The free() * matters: STRICT_REQUIRE returns, and `out` is already allocated. */ - if (items && (!items[i] || items[i]->type != VAL_NUM) - && (g_strict || (items[i] && items[i]->type == VAL_BOOL))) { /* #1637: a bool in every mode */ + if (data->type == VAL_LIST && list_elem_type(data, i) != VAL_NUM + && (g_strict || list_elem_type(data, i) == VAL_BOOL)) { /* #1637: a bool in every mode */ free(out); rt_error(EK_TYPE, 0, "write_bytes: expected every element to be a number"); return make_null(); } - double dv = items ? (items[i] && items[i]->type == VAL_NUM ? eigs_num_arg(items[i], __func__) : 0.0) - : buffer_read_num(data, i); + double dv = data->type == VAL_LIST + ? eigs_slot_elem_num(list_slot(data, i), __func__) + : buffer_read_num(data, i); if (g_has_error) { free(out); return make_null(); } out[i] = finite_num_to_byte(dv); } diff --git a/tools/container_migrated_files.txt b/tools/container_migrated_files.txt index b9e76cd1..a79e35ef 100644 --- a/tools/container_migrated_files.txt +++ b/tools/container_migrated_files.txt @@ -8,3 +8,5 @@ src/builtins_tensor.c src/model_infer.c src/model_train.c src/model_io.c +src/builtins_buf.c +src/builtins_host.c diff --git a/tools/strict_shape_contract.py b/tools/strict_shape_contract.py index d0d64bbe..293826b2 100644 --- a/tools/strict_shape_contract.py +++ b/tools/strict_shape_contract.py @@ -53,7 +53,7 @@ def functions(sources): # Deliberately remove annotations before candidate discovery. code = re.sub(r'STRICT_LIST_MAX\([^;]*;', '', code) # data.list or its #1665 container.h accessors (list_get_*/list_iter_*/...) - direct = bool(re.search(r'\bVAL_LIST\b|data\.list|\blist_(?:get|set|iter|values)_\w*\(|\bARG_COUNT\b|\bARG_AT\b', code)) + direct = bool(re.search(r'\bVAL_LIST\b|data\.list|\blist_(?:get|set|iter|values)_\w*\(|\blist_sort\(|\bARG_COUNT\b|\bARG_AT\b', code)) direct |= 'arg->data.dict' in code and bool(re.search(r'\bmake_list\s*\(', code)) helpers = set() for call in re.finditer(r'\b([A-Za-z_]\w*)\s*\(', code): diff --git a/tools/strict_shape_contracts.json b/tools/strict_shape_contracts.json index de2707b4..1ae2619c 100644 --- a/tools/strict_shape_contracts.json +++ b/tools/strict_shape_contracts.json @@ -387,11 +387,11 @@ ], "disposition": "exempt", "body_sha256": [ - "3d0d2c08324818d4ac65fe020224d685a9aac0e415d7bb69f54113b24a90aba0" + "9800ff3dcb6c1929c5b9326884f3d1a9cf99668756e25da259ba7dc962e198ee" ], "source_sha256": { "builtin_buf_from_list": [ - "3d0d2c08324818d4ac65fe020224d685a9aac0e415d7bb69f54113b24a90aba0" + "9800ff3dcb6c1929c5b9326884f3d1a9cf99668756e25da259ba7dc962e198ee" ] } }, @@ -503,11 +503,11 @@ ], "disposition": "exempt", "body_sha256": [ - "0f2463d9f7d4223393269796d4688a5d8fa708244de3f974f0e2f62c8cb0b540" + "2fd695baaa8e9743399e40a9483778ca9c3bda2b1d297f012b6b844fc5806103" ], "source_sha256": { "builtin_buffer": [ - "0f2463d9f7d4223393269796d4688a5d8fa708244de3f974f0e2f62c8cb0b540" + "2fd695baaa8e9743399e40a9483778ca9c3bda2b1d297f012b6b844fc5806103" ], "eigs_list_num": [ "25755c9b1f519fb0447e2d648dc0272419914db805f9249954cd2e146b48a3bc" @@ -772,11 +772,11 @@ ], "disposition": "exempt", "body_sha256": [ - "268d0eea61701a8101ef750b078302f77890f8baf08b211aebb51c75ce87293d" + "167f0efe94c146d6daa77ed91fd3ef73368fcfacfd373a2ee91ba6f5bccc9e0d" ], "source_sha256": { "builtin_exec_capture": [ - "268d0eea61701a8101ef750b078302f77890f8baf08b211aebb51c75ce87293d" + "167f0efe94c146d6daa77ed91fd3ef73368fcfacfd373a2ee91ba6f5bccc9e0d" ], "eigs_list_num": [ "25755c9b1f519fb0447e2d648dc0272419914db805f9249954cd2e146b48a3bc" @@ -807,11 +807,11 @@ ], "disposition": "exempt", "body_sha256": [ - "1872757a55392e54f959bd7659f1784ef0af3a43f4a6a8fc964c82cb475caea7" + "37cace163aae93897420ade0a6cb5ad56c3c7a3dfa43d351c93e299a1f4e3d57" ], "source_sha256": { "builtin_f64_from_bytes": [ - "1872757a55392e54f959bd7659f1784ef0af3a43f4a6a8fc964c82cb475caea7" + "37cace163aae93897420ade0a6cb5ad56c3c7a3dfa43d351c93e299a1f4e3d57" ] } }, @@ -1151,10 +1151,10 @@ "d89562220316e85c2ed110b250eee934769205aab21a2f3bc76a9804aa171060" ], "strict_numeric_byte_list": [ - "79f5f890f930f0eec678dc9851a7656462c94eeffc5468bccf7ee536988f68e3" + "c44801e4253c003e32d5daa43ec63454efc8faa0b13403ccd8f6e7b7bbe92b7e" ], "zlib_bytes_arg": [ - "11bf36d12e06d6f30fe673a5868e7f5db8888e3fe70ee45c0bc34df81acf2c63" + "482e756d657040d3c334c618e569d1824ed17c26f49a826b564aec1b0e86e5d3" ], "zlib_inflate_impl": [ "a54f1d8a2b596ca7c363f20303516358bf5992479e5aadc7ea6f2536e2089914" @@ -1358,11 +1358,11 @@ ], "disposition": "exempt", "body_sha256": [ - "94c3dd22d5e23b8370953c33ec40911a2bdc883501c741e689efe1defbed8b1f" + "9f31a265aef07d6971eb0c4eeab2f799f458d5fdd5ff977e0ab84b8b9d61b043" ], "source_sha256": { "builtin_ls": [ - "94c3dd22d5e23b8370953c33ec40911a2bdc883501c741e689efe1defbed8b1f" + "9f31a265aef07d6971eb0c4eeab2f799f458d5fdd5ff977e0ab84b8b9d61b043" ] } }, @@ -2146,14 +2146,14 @@ ], "disposition": "exempt", "body_sha256": [ - "90f545588091252200b754a2ff1764b111a8d0010212b8c10d49bb0064e1bb1f" + "aff6b5f42bc298bbd9e89a1b3b4e6869e6675974152841f17a47bee7a7cde312" ], "source_sha256": { "builtin_str_from_bytes": [ - "90f545588091252200b754a2ff1764b111a8d0010212b8c10d49bb0064e1bb1f" + "aff6b5f42bc298bbd9e89a1b3b4e6869e6675974152841f17a47bee7a7cde312" ], "strict_numeric_byte_list": [ - "79f5f890f930f0eec678dc9851a7656462c94eeffc5468bccf7ee536988f68e3" + "c44801e4253c003e32d5daa43ec63454efc8faa0b13403ccd8f6e7b7bbe92b7e" ] } },