static private function translateFilter ($filter, $input)
  {
    // Filter expressions syntax: filter arg1,...argN

    if (preg_match ('/^\S+\s*?\(/', $filter))
      self::filterSyntaxError ($filter, "Filter arguments must not be enclosed in <kbd>()</kbd>");
    list ($name, $argsStr) = str_extractSegment ($filter, '/\s+/');
    $args = [];

    while ($argsStr !== '') {
      list ($subExp, $op) = self::translateSimpleExpression ($argsStr);
      if ($op && $op != ',')
        self::filterSyntaxError ($filter, "Filter arguments must be simple expressions; operators are not allowed.
<p>Offending character: <kbd>$op</kbd>");
      $args[] = $subExp;
    }

    if ($name == '*') {
      if ($args) self::filterSyntaxError ($filter, "Raw output filter function <kbd>*</kbd> must have no arguments.");
      return "(new RawText($input))";
    }
    return sprintf ('%s->filter(\'%s\',%s%s%s)', self::BINDER_PARAM, addslashes ($name), $input, $args ? ',' : '',
      implode (',', $args));
  }