Commit f4d067391 for llama.cpp
commit f4d0673917c75493c73fc9b64ab42841600ba944
Author: Xuan Son Nguyen <son@huggingface.co>
Date: Sun Nov 15 19:35:31 2026 +0100
Revert "jinja: add 4 missing features"
This reverts commit a681a53b6092d57597b9e66f2fc9d4556155b9e4.
diff --git a/common/jinja/lexer.cpp b/common/jinja/lexer.cpp
index 7338d2eb1..bf2dfacda 100644
--- a/common/jinja/lexer.cpp
+++ b/common/jinja/lexer.cpp
@@ -6,7 +6,6 @@
#include <charconv>
#include <functional>
#include <map>
-#include <set>
#include <string>
#include <vector>
@@ -273,12 +272,6 @@ lexer_result lexer::tokenize(const std::string & source) {
if (last_token_type == token::text || last_token_type == token::eof) {
throw lexer_exception(std::string("unexpected character: ") + ch, source, pos);
}
- // keyword followed by an operand, e.g. `x if c else -1`; `a.else - 1` is still binary
- static const std::set<std::string> operand_keywords = { "if", "else", "and", "or", "not", "in", "is" };
- const bool is_attr = tokens.size() >= 2 && tokens[tokens.size() - 2].t == token::dot;
- if (last_token_type == token::identifier && !is_attr && operand_keywords.count(tokens.back().value)) {
- last_token_type = token::eof; // handle as unary below
- }
switch (last_token_type) {
case token::identifier:
case token::numeric_literal:
diff --git a/common/jinja/lexer.h b/common/jinja/lexer.h
index 4a7ea83a3..3f4ebb62a 100644
--- a/common/jinja/lexer.h
+++ b/common/jinja/lexer.h
@@ -141,7 +141,6 @@ struct lexer {
{"~", token::additive_binary_operator},
{"**", token::power_operator},
{"*", token::multiplicative_binary_operator},
- {"//", token::multiplicative_binary_operator},
{"/", token::multiplicative_binary_operator},
{"%", token::multiplicative_binary_operator},
// Assignment operator
diff --git a/common/jinja/runtime.cpp b/common/jinja/runtime.cpp
index aae67cab0..8bd8ab1c8 100644
--- a/common/jinja/runtime.cpp
+++ b/common/jinja/runtime.cpp
@@ -196,25 +196,6 @@ static value exec_binary_op(context & ctx, const token & op, value left_val, val
} else if (op.value == "/") {
JJ_DEBUG("Division operation: %f / %f", a, b);
return mk_val<value_float>(a / b);
- } else if (op.value == "//") {
- // python semantics: round toward -inf
- if (is_val<value_int>(left_val) && is_val<value_int>(right_val)) {
- const int64_t x = left_val->as_int();
- const int64_t y = right_val->as_int();
- if (y == 0) {
- throw std::runtime_error("integer division by zero");
- }
- if (y == -1) {
- // INT64_MIN / -1 is UB, wrap around instead
- return mk_val<value_int>((int64_t) (0 - (uint64_t) x));
- }
- int64_t q = x / y;
- if (x % y != 0 && (x < 0) != (y < 0)) {
- q -= 1;
- }
- return mk_val<value_int>(q);
- }
- return mk_val<value_float>(std::floor(a / b));
} else if (op.value == "%") {
double rem = std::fmod(a, b);
JJ_DEBUG("Modulo operation: %f %% %f = %f", a, b, rem);
@@ -293,17 +274,12 @@ static value exec_binary_op(context & ctx, const token & op, value left_val, val
// String membership
if (is_val<value_string>(left_val) && is_val<value_string>(right_val)) {
// case: "a" in "abc"
- if (op.value == "in" || op.value == "not in") {
- bool member = test_is_in();
- return mk_val<value_bool>(op.value == "in" ? member : !member);
+ bool member = test_is_in();
+ if (op.value == "in") {
+ return mk_val<value_bool>(member);
+ } else if (op.value == "not in") {
+ return mk_val<value_bool>(!member);
}
- // case: "a" < "b"; UTF-8 byte order is the same as codepoint order, like python
- const std::string a = left_val->as_string().str();
- const std::string b = right_val->as_string().str();
- if (op.value == "<") { return mk_val<value_bool>(a < b); }
- if (op.value == ">") { return mk_val<value_bool>(a > b); }
- if (op.value == "<=") { return mk_val<value_bool>(a <= b); }
- if (op.value == ">=") { return mk_val<value_bool>(a >= b); }
}
// Value key in object
diff --git a/common/jinja/value.cpp b/common/jinja/value.cpp
index c75fa1d51..561a4b86a 100644
--- a/common/jinja/value.cpp
+++ b/common/jinja/value.cpp
@@ -1101,25 +1101,8 @@ const func_builtins & value_bool_t::get_builtins() const {
return builtins;
}
-static value array_sum(const func_args & args) {
- args.ensure_kwargs({"attribute", "start"});
- args.ensure_count(1, 3);
- args.ensure_vals<value_array>();
- value undef = mk_val<value_undefined>();
- value attribute = args.get_kwarg_or_pos("attribute", 1);
- value start = args.get_kwarg_or_pos("start", 2);
- // same as the + operator: compute in double, int result if all operands are int
- bool is_float = is_val<value_float>(start);
- double sum = start->is_undefined() ? 0.0 : start->as_float();
- for (const auto & item : args.get_pos(0)->as_array()) {
- value v = attribute->is_undefined() ? item : get_attribute(item, attribute, undef);
- if (!is_val<value_int>(v) && !is_val<value_float>(v)) {
- throw raised_exception("sum: unsupported operand type " + v->type());
- }
- is_float = is_float || is_val<value_float>(v);
- sum += v->as_float();
- }
- return is_float ? value(mk_val<value_float>(sum)) : value(mk_val<value_int>(static_cast<int64_t>(sum)));
+[[noreturn]] static value array_sum_not_implemented(const func_args &) {
+ throw not_implemented_exception("Array sum builtin not implemented");
}
const func_builtins & value_array_t::get_builtins() const {
@@ -1188,7 +1171,7 @@ const func_builtins & value_array_t::get_builtins() const {
{"select", select_or_reject<false, false>},
{"rejectattr", select_or_reject<true, true>},
{"reject", select_or_reject<true, false>},
- {"sum", array_sum},
+ {"sum", array_sum_not_implemented},
{"join", [](const func_args & args) -> value {
args.ensure_kwargs({"d", "attribute"});
args.ensure_count(1, 3);
diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp
index 8fd275222..d52f1af9c 100644
--- a/tests/test-jinja.cpp
+++ b/tests/test-jinja.cpp
@@ -657,30 +657,6 @@ static void test_expressions(testing & t) {
"20"
);
- test_template(t, "floor division",
- "{{ 7 // 2 }},{{ -7 // 2 }},{{ 7 // -2 }},{{ 7.5 // 2 }},{{ a // b }}",
- {{"a", 10}, {"b", 3}},
- "3,-4,-4,3.0,3"
- );
-
- test_template(t, "string comparison",
- "{{ 'b' > 'a' }},{{ 'VBD' > 'VB' }},{{ 'a' <= 'a' }},{{ 'Z' < 'a' }},{{ 'ab' >= 'b' }}",
- json::object(),
- "True,True,True,True,False"
- );
-
- test_template(t, "unary minus after keyword",
- "{{ 1 if false else -1 }},{{ not -1 }},{{ x and -2 }},{{ -3 if x }}",
- {{"x", true}},
- "-1,False,-2,-3"
- );
-
- test_template(t, "binary minus after keyword attribute",
- "{{ a.else - 1 }}",
- {{"a", {{"else", 3}}}},
- "2"
- );
-
test_template(t, "string concat ~",
"{{ 'hello' ~ ' ' ~ 'world' }}",
json::object(),
@@ -2214,12 +2190,6 @@ static void test_array_methods(testing & t) {
"6"
);
- test_template(t, "array|sum",
- "{{ [1, 2.5, 3]|sum }},{{ [1, 2]|sum(start=10) }},{{ items|sum(attribute='w') }},{{ []|sum }}",
- {{"items", json::array({{{"w", 1}}, {{"w", 2}}})}},
- "6.5,13,3,0"
- );
-
test_template(t, "array|min",
"{{ [tool_calls_count, tool_sep_count]|min }}",
{{"tool_calls_count", 2}, {"tool_sep_count", 1}},