openlang

invalid command name "Dana" из обычной строки в TSV, что?

Короче, эта штука гоняет меня по кругу. Tcl 9.0 на Arch, tclsh main.tcl, небольшой отчёт по заказам для сайта клиента, который торгует хозтоварами для строительства.

У меня в config.tcl было одно правило (total >= 200), и всё работало. Потом я добавил второе правило, чтобы заказы с комментарием клиента тоже помечались:

set ::flag_rules {
    {total >= 200}
    {note ne {}}
}

Теперь прогон падает где-то посередине с invalid command name "Dana". Трейс указывает на строку с expr в rule_match:

proc rule_match {row rule} {
    lassign $rule field op value
    set have [dict get $row $field]
    return [expr "\"$have\" $op \"$value\""]
}

"Dana" нигде в моём коде не команда. Она в данных. В orders.tsv у одного из крупных заказов такой комментарий:

1003	Petrakis Plumbing	1250.75	call [Dana] before shipping

Остальные комментарии (например, "leave at side door") проходят нормально. Я напечатал dict строки прямо перед падением, и он выглядит совершенно обычно. Табы разделили правильно, все четыре поля на месте, комментарий цел. Так что я час копался в load_orders, уверенный, что в экспорте клиента какая-то странная кодировка или лишний байт. Проверил в Neovim через :set list, табы выглядят как табы. (Кстати, почему в их экспорте у строк с пустым комментарием стоит хвостовой таб, а у 1005 нет? Другая проблема, другой день.)

Чего я не понимаю: как строка, лежащая в dict, превращается в вызов команды? Ничего же её не eval'ит. Почему только эта строка?

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Дополню свою тему, потому что я нашёл причину, и всё это время виноват был я сам.

    Дело не в данных и не в TSV. Дело в строке expr "...". Раз я собираю выражение в двойных кавычках, Tcl сначала подставляет $have. Потом expr разбирает результат, и [Dana] внутри строки в кавычках в выражении проходит через подстановку команд. То есть текст примечания выполнился как код. В "leave at side door" просто нечего подставлять. (Правило по total ни разу не упало, потому что 1250.75 это всего лишь число.)

    Решение: перестать склеивать строки и сделать оператор командой:

    proc rule_match {row rule} {
        lassign $rule field op value
        return [::tcl::mathop::$op [dict get $row $field] $value]
    }

    ne и >= там оба есть. Документация: https://www.tcl-lang.org/man/tcl9.0/TclCmd/mathop.htm

    Ещё на странице expr сказано заключать выражения в фигурные скобки, и не зря. Я читал эту страницу много лет назад, видимо, не усвоив. Забавно, что час в Neovim за поиском лишнего байта обходится дороже, чем тридцать секунд чтения мануала.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Один и тот же Int, два таргета, два разных результата

    Один и тот же исходник, один и тот же файл, две платформы. На JS один участник пропадает. Ни ошибки, ни предупреждения. Меня…

    Ответы 0Последняя активность gleam
  2. pure host-функцию кэшируют, и запись в её аргумент просто пропадает

    Всю неделю всем рассказываю про memo-кэш в реестре моего игрушечного вычислителя (D, проект на выходные). Правило: если хост-…

    Ответы 2Последняя активность d
  3. тот же parseServices, а плохая строка ломает только на этапе сборки?

    Заменил auto на enum для встроенной таблицы, раз она никогда не меняется, верно? Теперь smtp 25 (без proto) ломает dub build,…

    Ответы 2Последняя активность d