--- Gemma4e tool-args parser ------------------------------------------------- The model emits relaxed JSON for tool arguments: - keys are bare identifiers (e.g. `name:`) — sometimes also "..." quoted - string values are delimited by <|"|>...<|"|>, but the model frequently omits the opener and/or replaces the closer with a plain `"` - values can also be objects {..}, arrays [..], booleans, null, o
| 31 | // |
| 32 | // We rewrite the input into well-formed JSON via recursive-descent. |
| 33 | struct Gemma4eArgsParser { |
| 34 | const std::string& s; |
| 35 | size_t i = 0; |
| 36 | static constexpr size_t marker_len = 5; |
| 37 | static constexpr const char* quote_marker_lit = "<|\"|>"; |
| 38 | |
| 39 | explicit Gemma4eArgsParser(const std::string& src) : s(src) {} |
| 40 | |
| 41 | void skip_ws() { |
| 42 | while (i < s.size() && |
| 43 | std::isspace(static_cast<unsigned char>(s[i]))) ++i; |
| 44 | } |
| 45 | void skip_ws_at(size_t& pos) const { |
| 46 | while (pos < s.size() && |
| 47 | std::isspace(static_cast<unsigned char>(s[pos]))) ++pos; |
| 48 | } |
| 49 | bool match_marker(size_t pos) const { |
| 50 | return pos + marker_len <= s.size() && |
| 51 | s.compare(pos, marker_len, quote_marker_lit) == 0; |
| 52 | } |
| 53 | |
| 54 | static void json_escape_char(std::string& out, char c) { |
| 55 | switch (c) { |
| 56 | case '"': out.append("\\\""); break; |
| 57 | case '\\': out.append("\\\\"); break; |
| 58 | case '\n': out.append("\\n"); break; |
| 59 | case '\r': out.append("\\r"); break; |
| 60 | case '\t': out.append("\\t"); break; |
| 61 | case '\b': out.append("\\b"); break; |
| 62 | case '\f': out.append("\\f"); break; |
| 63 | default: |
| 64 | if (static_cast<unsigned char>(c) < 0x20) { |
| 65 | char buf[8]; |
| 66 | std::snprintf(buf, sizeof(buf), "\\u%04x", |
| 67 | static_cast<unsigned char>(c)); |
| 68 | out.append(buf); |
| 69 | } else { |
| 70 | out.push_back(c); |
| 71 | } |
| 72 | break; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | bool match_word(const char* w, size_t len) const { |
| 77 | if (i + len > s.size()) return false; |
| 78 | if (s.compare(i, len, w) != 0) return false; |
| 79 | if (i + len == s.size()) return true; |
| 80 | unsigned char nc = static_cast<unsigned char>(s[i + len]); |
| 81 | return !(std::isalnum(nc) || nc == '_'); |
| 82 | } |
| 83 | |
| 84 | // Parse one JSON value. `terminators` is the set of chars that end a |
| 85 | // bare (undelimited) string at depth 0 (e.g. ",}" inside an object, |
| 86 | // ",]" inside an array, "" at the very top). |
| 87 | std::string parse_value(const std::string& terminators) { |
| 88 | skip_ws(); |
| 89 | if (i >= s.size()) return "null"; |
| 90 | char c = s[i]; |
nothing calls this directly
no outgoing calls
no test coverage detected