Merge branch 'upstream' into concedo_experimental

# Conflicts:
#	ggml/src/ggml-cpu/CMakeLists.txt
#	ggml/src/ggml-cpu/kleidiai/kernels.cpp
#	ggml/src/ggml-cpu/kleidiai/kernels.h
#	ggml/src/ggml-cpu/kleidiai/kleidiai.cpp
#	ggml/src/ggml-cpu/ops.cpp
#	ggml/src/ggml-cuda/mmq.cuh
#	ggml/src/ggml-hexagon/htp/hmx-queue.c
#	ggml/src/ggml-opencl/ggml-opencl.cpp
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_iq4_nl_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32_spec.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_1_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_k_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q5_0_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q5_1_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q5_k_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q6_k_f32.cl
#	ggml/src/ggml-opencl/kernels/gemv_noshuffle_q8_0_f32.cl
#	ggml/src/ggml-opencl/kernels/mul_mv_f16_f16.cl
#	ggml/src/ggml-opencl/kernels/mul_mv_f16_f32.cl
#	ggml/src/ggml-opencl/kernels/mul_mv_f16_f32_1row.cl
#	ggml/src/ggml-sycl/fattn-vec.hpp
#	tests/test-backend-ops.cpp
#	tests/test-chat-auto-parser.cpp
#	tests/test-export-graph-ops.cpp
#	tests/test-jinja.cpp
#	tests/test-llama-archs.cpp
#	tools/tokenize/tokenize.cpp
This commit is contained in:
Concedo
2026-07-15 15:39:31 +08:00
73 changed files with 6859 additions and 3973 deletions
+39
View File
@@ -753,11 +753,50 @@ const func_builtins & value_string_t::get_builtins() const {
res->val_str.mark_input_based_on(args.get_pos(0)->val_str);
return res;
}},
{"format", [](const func_args & args) -> value {
value val_input = args.get_pos(0);
if (!is_val<value_string>(val_input)) {
throw raised_exception("format() first argument must be a string");
}
const jinja::string & fmt = val_input->as_string();
const bool fmt_is_input = fmt.all_parts_are_input();
const std::string str = fmt.str();
jinja::string result;
std::string literal;
auto flush_literal = [&]() {
if (!literal.empty()) {
result.parts.push_back({fmt_is_input, literal});
literal.clear();
}
};
size_t arg_idx = 1; // positional args follow the format string
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] != '{') {
literal += str[i];
continue;
}
if (i + 1 >= str.size() || str[i + 1] != '}') {
throw not_implemented_exception("format() only supports simple '{}' placeholders");
}
++i;
flush_literal();
const jinja::string arg_str = args.get_pos(arg_idx++)->as_string();
result.parts.insert(result.parts.end(), arg_str.parts.begin(), arg_str.parts.end());
}
flush_literal();
return mk_val<value_string>(result);
}},
{"int", [](const func_args & args) -> value {
value val_input = args.get_pos(0);
value val_default = args.get_kwarg_or_pos("default", 1);
value val_base = args.get_kwarg_or_pos("base", 2);
const int base = val_base->is_undefined() ? 10 : val_base->as_int();
if (base != 0 && (base < 2 || base > 36)) {
// an out-of-range base makes std::stoi fail fast on the MSVC CRT instead of throwing
throw raised_exception("int() base must be 0 or between 2 and 36");
}
if (is_val<value_string>(val_input) == false) {
throw raised_exception("int() first argument must be a string");
}