Skip to content

Commit 3bacf1f

Browse files
gh-104: Add APPEND.
1 parent 708cd15 commit 3bacf1f

3 files changed

Lines changed: 61 additions & 0 deletions

File tree

docs/SPECIFICATION.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,8 @@
807807
808808
- `TNS: SCAT(TNS: src, TNS: dst, TNS: ind)` = MUST return a copy of `dst` with a rectangular slice replaced by `src`. `ind` MUST encode one inclusive `[lo, hi]` range pair per destination dimension. The selected slice shape MUST exactly match the shape of `src`, and out-of-range indices MUST raise a runtime error.
809809
810+
- `TNS: APPEND(ANY: elem, TNS: tns)` = MUST return a new one-dimensional tensor equal to `tns` with `elem` appended as the last element. If `tns` is not one-dimensional the operator MUST raise a runtime error. Prefix `TNS` values MAY contain heterogeneous element types; `APPEND` therefore MUST accept any element type and simply append it as the last element.
811+
810812
- `TNS: FILL(TNS: tensor, ANY: value)` = MUST return a new tensor with the same shape as `tensor`, filled with `value`. `value` MUST satisfy the target tensor's element-type constraints.
811813
812814
- `TNS: CONV(TNS: x, TNS: kernel, INT: stride_w = 1, INT: stride_h = 1, INT: pad_w = 0, INT: pad_h = 0, TNS: bias = [])` = MUST support both the legacy two-argument N-dimensional convolution form and the extended 2-D multi-output form. In the legacy form, `kernel` MUST have the same rank as `x`, every kernel dimension length MUST be odd, boundary sampling MUST clamp to the nearest valid index, and the result MUST have the same shape as `x`. In the extended form, when any keyword argument is supplied and `x` is rank 3 while `kernel` is rank 4 with shape `[kw, kh, in_c, out_c]`, the operator MUST perform 2-D convolution with the given strides, explicit zero padding, and optional per-output-channel bias, returning shape `[out_w, out_h, out_c]`. Where both inputs are `INT`, the output MUST be `INT`; otherwise it MUST be `FLT`.

src/builtins.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3716,6 +3716,46 @@ static Value builtin_fill(Interpreter* interp, Value* args, int argc, Expr** arg
37163716
return out;
37173717
}
37183718

3719+
// APPEND: append a single element to a 1-D tensor and return a new tensor
3720+
static Value builtin_append(Interpreter* interp, Value* args, int argc, Expr** arg_nodes, Env* env, int line, int col) {
3721+
(void)arg_nodes; (void)env; (void)argc;
3722+
if (args[1].type != VAL_TNS) {
3723+
RUNTIME_ERROR(interp, "APPEND expects (ANY, TNS)", line, col);
3724+
}
3725+
Tensor* t = args[1].as.tns;
3726+
if (!t) {
3727+
RUNTIME_ERROR(interp, "Invalid target tensor", line, col);
3728+
}
3729+
if (t->ndim != 1) {
3730+
RUNTIME_ERROR(interp, "APPEND target must be 1-D TNS", line, col);
3731+
}
3732+
3733+
size_t old_len = t->shape[0];
3734+
size_t new_len = old_len + 1;
3735+
size_t shape[1] = { new_len };
3736+
Value out = value_tns_new(t->elem_type, 1, shape);
3737+
Tensor* ot = out.as.tns;
3738+
3739+
// copy existing elements
3740+
for (size_t i = 0; i < old_len; i++) {
3741+
ot->data[i] = value_copy(t->data[i]);
3742+
}
3743+
3744+
// append the provided element (deep-copy containers to avoid shared mutation)
3745+
if (args[0].type == VAL_TNS || args[0].type == VAL_MAP) {
3746+
ot->data[new_len - 1] = value_deep_copy(args[0]);
3747+
} else {
3748+
ot->data[new_len - 1] = value_copy(args[0]);
3749+
}
3750+
3751+
if (!writeback_ptr_node(interp, arg_nodes ? arg_nodes[1] : NULL, env, out, "APPEND", line, col)) {
3752+
value_free(out);
3753+
return value_null();
3754+
}
3755+
3756+
return out;
3757+
}
3758+
37193759
// SCAT: return a copy of dst with a rectangular slice replaced by src.
37203760
// Args: SCAT(TNS: src, TNS: dst, TNS: ind)
37213761
static Value builtin_scat(Interpreter* interp, Value* args, int argc, Expr** arg_nodes, Env* env, int line, int col) {
@@ -8043,6 +8083,7 @@ static BuiltinFunction builtins_table[] = {
80438083
{"TLEN", 2, 2, builtin_tlen},
80448084
{"TFLIP", 2, 2, builtin_tflip},
80458085
{"SCAT", 3, 3, builtin_scat},
8086+
{"APPEND", 2, 2, builtin_append},
80468087
{"MADD", 2, 2, builtin_madd},
80478088
{"MSUB", 2, 2, builtin_msub},
80488089
{"MMUL", 2, 2, builtin_mmul},

tests/test2.pre

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,24 @@ DEL(src_scat)
459459
DEL(ind_scat)
460460
PRINT("SCAT: PASS\n")
461461

462+
! --- APPEND operator ---
463+
PRINT("Testing APPEND...")
464+
TNS: a_append = [0d1, 0d2]
465+
TNS: b_append = APPEND(0d3, a_append)
466+
ASSERT(EQ(b_append, [0d1, 0d2, 0d3]))
467+
DEL(a_append)
468+
DEL(b_append)
469+
470+
TNS: t_append = [0d1, 0d2]
471+
APPEND(0d3, @t_append)
472+
ASSERT(EQ(t_append[0d3], 0d3))
473+
DEL(t_append)
474+
475+
TNS: s_append = ["a", "b"]
476+
ASSERT(EQ(APPEND("c", s_append), ["a", "b", "c"]))
477+
DEL(s_append)
478+
PRINT("APPEND: PASS\n")
479+
462480
! --- Tensor-scalar arithmetic operators ---
463481
PRINT("Testing tensor-scalar arithmetic...")
464482
TNS: ta = [0b1, 0b10]

0 commit comments

Comments
 (0)