2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/ASTFunction.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
|
2020-08-20 02:01:40 +00:00
|
|
|
#include <Common/SipHash.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2020-11-09 16:05:40 +00:00
|
|
|
#include <IO/Operators.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <IO/WriteBufferFromString.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTLiteral.h>
|
|
|
|
#include <Parsers/ASTSubquery.h>
|
|
|
|
#include <Parsers/ASTWithAlias.h>
|
2015-08-05 21:39:42 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
void ASTFunction::appendColumnNameImpl(WriteBuffer & ostr) const
|
2016-05-03 23:19:14 +00:00
|
|
|
{
|
2018-06-27 16:34:11 +00:00
|
|
|
writeString(name, ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (parameters)
|
|
|
|
{
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar('(', ostr);
|
|
|
|
for (auto it = parameters->children.begin(); it != parameters->children.end(); ++it)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (it != parameters->children.begin())
|
2018-06-27 16:34:11 +00:00
|
|
|
writeCString(", ", ostr);
|
|
|
|
(*it)->appendColumnName(ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar(')', ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar('(', ostr);
|
2020-12-04 02:15:44 +00:00
|
|
|
if (arguments)
|
|
|
|
for (auto it = arguments->children.begin(); it != arguments->children.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != arguments->children.begin())
|
|
|
|
writeCString(", ", ostr);
|
|
|
|
(*it)->appendColumnName(ostr);
|
|
|
|
}
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar(')', ostr);
|
2020-12-16 21:44:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
if (window_name)
|
|
|
|
{
|
|
|
|
writeCString(" over ", ostr);
|
|
|
|
window_name->appendColumnName(ostr);
|
|
|
|
}
|
|
|
|
*/
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
2017-04-02 17:37:49 +00:00
|
|
|
/** Get the text that identifies this element. */
|
2018-12-07 12:34:40 +00:00
|
|
|
String ASTFunction::getID(char delim) const
|
2016-05-03 23:19:14 +00:00
|
|
|
{
|
2018-12-07 12:34:40 +00:00
|
|
|
return "Function" + (delim + name);
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ASTPtr ASTFunction::clone() const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTFunction>(*this);
|
|
|
|
res->children.clear();
|
2016-05-03 23:19:14 +00:00
|
|
|
|
2018-02-24 01:31:42 +00:00
|
|
|
if (arguments) { res->arguments = arguments->clone(); res->children.push_back(res->arguments); }
|
|
|
|
if (parameters) { res->parameters = parameters->clone(); res->children.push_back(res->parameters); }
|
2016-05-03 23:19:14 +00:00
|
|
|
|
2020-12-16 21:44:05 +00:00
|
|
|
if (window_name)
|
|
|
|
{
|
|
|
|
res->set(res->window_name, window_name->clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window_partition_by)
|
|
|
|
{
|
|
|
|
res->set(res->window_partition_by, window_partition_by->clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window_order_by)
|
|
|
|
{
|
|
|
|
res->set(res->window_order_by, window_order_by->clone());
|
|
|
|
}
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return res;
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-08-20 02:01:40 +00:00
|
|
|
void ASTFunction::updateTreeHashImpl(SipHash & hash_state) const
|
|
|
|
{
|
|
|
|
hash_state.update(name.size());
|
|
|
|
hash_state.update(name);
|
|
|
|
IAST::updateTreeHashImpl(hash_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
ASTPtr ASTFunction::toLiteral() const
|
|
|
|
{
|
|
|
|
if (!arguments) return {};
|
|
|
|
|
|
|
|
if (name == "array")
|
|
|
|
{
|
|
|
|
Array array;
|
|
|
|
|
|
|
|
for (const auto & arg : arguments->children)
|
|
|
|
{
|
|
|
|
if (auto * literal = arg->as<ASTLiteral>())
|
|
|
|
array.push_back(literal->value);
|
|
|
|
else if (auto * func = arg->as<ASTFunction>())
|
|
|
|
{
|
|
|
|
if (auto func_literal = func->toLiteral())
|
|
|
|
array.push_back(func_literal->as<ASTLiteral>()->value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/// Some of the Array arguments is not literal
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_shared<ASTLiteral>(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-05 15:57:59 +00:00
|
|
|
/** A special hack. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal,
|
2019-02-10 19:11:47 +00:00
|
|
|
* we will highlight unescaped metacharacters % and _ in string literal for convenience.
|
2019-02-10 19:21:08 +00:00
|
|
|
* Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes.
|
2019-02-10 19:11:47 +00:00
|
|
|
* With highlighting we make it clearly obvious.
|
|
|
|
*
|
|
|
|
* Another case is regexp match. Suppose the user types match(URL, 'www.yandex.ru'). It often means that the user is unaware that . is a metacharacter.
|
|
|
|
*/
|
|
|
|
static bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, const IAST::FormatSettings & settings, const char * metacharacters)
|
|
|
|
{
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * literal = node->as<ASTLiteral>())
|
2019-02-10 19:11:47 +00:00
|
|
|
{
|
|
|
|
if (literal->value.getType() == Field::Types::String)
|
|
|
|
{
|
|
|
|
auto string = applyVisitor(FieldVisitorToString(), literal->value);
|
|
|
|
|
|
|
|
unsigned escaping = 0;
|
|
|
|
for (auto c : string)
|
|
|
|
{
|
|
|
|
if (c == '\\')
|
|
|
|
{
|
|
|
|
settings.ostr << c;
|
|
|
|
if (escaping == 2)
|
|
|
|
escaping = 0;
|
|
|
|
++escaping;
|
|
|
|
}
|
|
|
|
else if (nullptr != strchr(metacharacters, c))
|
|
|
|
{
|
|
|
|
if (escaping == 2) /// Properly escaped metacharacter
|
|
|
|
settings.ostr << c;
|
|
|
|
else /// Unescaped metacharacter
|
|
|
|
settings.ostr << "\033[1;35m" << c << "\033[0m";
|
|
|
|
escaping = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
settings.ostr << c;
|
|
|
|
escaping = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-09 07:41:38 +00:00
|
|
|
ASTSelectWithUnionQuery * ASTFunction::tryGetQueryArgument() const
|
|
|
|
{
|
|
|
|
if (arguments && arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
return arguments->children[0]->as<ASTSelectWithUnionQuery>();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-06 23:46:15 +00:00
|
|
|
void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
2015-08-06 03:26:27 +00:00
|
|
|
{
|
2020-09-08 20:34:10 +00:00
|
|
|
frame.expression_list_prepend_whitespace = false;
|
2017-04-01 07:20:54 +00:00
|
|
|
FormatStateStacked nested_need_parens = frame;
|
|
|
|
FormatStateStacked nested_dont_need_parens = frame;
|
2018-05-17 15:17:07 +00:00
|
|
|
nested_need_parens.need_parens = true;
|
|
|
|
nested_dont_need_parens.need_parens = false;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-09-09 07:41:38 +00:00
|
|
|
if (auto * query = tryGetQueryArgument())
|
2020-08-28 14:07:14 +00:00
|
|
|
{
|
|
|
|
std::string nl_or_nothing = settings.one_line ? "" : "\n";
|
|
|
|
std::string indent_str = settings.one_line ? "" : std::string(4u * frame.indent, ' ');
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name << "(" << nl_or_nothing;
|
|
|
|
FormatStateStacked frame_nested = frame;
|
|
|
|
frame_nested.need_parens = false;
|
|
|
|
++frame_nested.indent;
|
|
|
|
query->formatImpl(settings, state, frame_nested);
|
|
|
|
settings.ostr << nl_or_nothing << indent_str << ")";
|
|
|
|
return;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Should this function to be written as operator?
|
|
|
|
bool written = false;
|
|
|
|
if (arguments && !parameters)
|
|
|
|
{
|
|
|
|
if (arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
|
|
|
"negate", "-",
|
|
|
|
"not", "NOT ",
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
|
|
|
if (0 == strcmp(name.c_str(), func[0]))
|
|
|
|
{
|
2019-06-16 22:51:09 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
|
|
|
|
2017-04-02 17:37:49 +00:00
|
|
|
/** A particularly stupid case. If we have a unary minus before a literal that is a negative number
|
|
|
|
* "-(-1)" or "- -1", this can not be formatted as `--1`, since this will be interpreted as a comment.
|
|
|
|
* Instead, add a space.
|
|
|
|
* PS. You can not just ask to add parentheses - see formatImpl for ASTLiteral.
|
2017-04-01 07:20:54 +00:00
|
|
|
*/
|
2019-03-11 13:22:51 +00:00
|
|
|
if (name == "negate" && arguments->children[0]->as<ASTLiteral>())
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ' ';
|
|
|
|
|
|
|
|
arguments->formatImpl(settings, state, nested_need_parens);
|
|
|
|
written = true;
|
2019-06-16 22:51:09 +00:00
|
|
|
|
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 19:12:58 +00:00
|
|
|
/** need_parens - do we need parentheses around the expression with the operator.
|
2017-04-02 17:37:49 +00:00
|
|
|
* They are needed only if this expression is included in another expression with the operator.
|
|
|
|
*/
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!written && arguments->children.size() == 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2017-12-09 20:56:53 +00:00
|
|
|
"multiply", " * ",
|
|
|
|
"divide", " / ",
|
|
|
|
"modulo", " % ",
|
|
|
|
"plus", " + ",
|
|
|
|
"minus", " - ",
|
|
|
|
"notEquals", " != ",
|
|
|
|
"lessOrEquals", " <= ",
|
|
|
|
"greaterOrEquals", " >= ",
|
|
|
|
"less", " < ",
|
|
|
|
"greater", " > ",
|
|
|
|
"equals", " = ",
|
|
|
|
"like", " LIKE ",
|
2020-07-05 15:57:59 +00:00
|
|
|
"ilike", " ILIKE ",
|
2017-12-09 20:56:53 +00:00
|
|
|
"notLike", " NOT LIKE ",
|
2020-07-05 15:57:59 +00:00
|
|
|
"notILike", " NOT ILIKE ",
|
2017-12-09 20:56:53 +00:00
|
|
|
"in", " IN ",
|
|
|
|
"notIn", " NOT IN ",
|
|
|
|
"globalIn", " GLOBAL IN ",
|
|
|
|
"globalNotIn", " GLOBAL NOT IN ",
|
2017-04-01 07:20:54 +00:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
|
|
|
if (0 == strcmp(name.c_str(), func[0]))
|
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
|
|
|
bool special_hilite = settings.hilite
|
2020-07-05 15:57:59 +00:00
|
|
|
&& (name == "like" || name == "notLike" || name == "ilike" || name == "notILike")
|
2019-02-10 19:11:47 +00:00
|
|
|
&& highlightStringLiteralWithMetacharacters(arguments->children[1], settings, "%_");
|
|
|
|
|
2019-05-16 19:12:58 +00:00
|
|
|
/// Format x IN 1 as x IN (1): put parens around rhs even if there is a single element in set.
|
|
|
|
const auto * second_arg_func = arguments->children[1]->as<ASTFunction>();
|
2019-05-16 22:51:26 +00:00
|
|
|
const auto * second_arg_literal = arguments->children[1]->as<ASTLiteral>();
|
2019-05-16 19:19:30 +00:00
|
|
|
bool extra_parents_around_in_rhs = (name == "in" || name == "notIn" || name == "globalIn" || name == "globalNotIn")
|
2019-05-19 19:22:51 +00:00
|
|
|
&& !second_arg_func
|
|
|
|
&& !(second_arg_literal
|
|
|
|
&& (second_arg_literal->value.getType() == Field::Types::Tuple
|
|
|
|
|| second_arg_literal->value.getType() == Field::Types::Array))
|
2019-05-16 19:55:18 +00:00
|
|
|
&& !arguments->children[1]->as<ASTSubquery>();
|
2019-05-16 19:12:58 +00:00
|
|
|
|
2019-05-16 19:19:30 +00:00
|
|
|
if (extra_parents_around_in_rhs)
|
2019-05-16 19:12:58 +00:00
|
|
|
{
|
|
|
|
settings.ostr << '(';
|
2019-05-16 19:55:18 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2019-05-16 19:12:58 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
}
|
|
|
|
|
2019-05-16 19:55:18 +00:00
|
|
|
if (!special_hilite && !extra_parents_around_in_rhs)
|
2019-02-10 19:11:47 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && 0 == strcmp(name.c_str(), "arrayElement"))
|
|
|
|
{
|
2019-06-16 22:51:09 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
2019-06-16 22:51:09 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ']' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
2019-06-16 22:51:09 +00:00
|
|
|
|
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && 0 == strcmp(name.c_str(), "tupleElement"))
|
|
|
|
{
|
2017-12-24 09:33:36 +00:00
|
|
|
/// It can be printed in a form of 'x.1' only if right hand side is unsigned integer literal.
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * lit = arguments->children[1]->as<ASTLiteral>())
|
2017-12-24 09:33:36 +00:00
|
|
|
{
|
|
|
|
if (lit->value.getType() == Field::Types::UInt64)
|
|
|
|
{
|
2019-06-16 22:42:06 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2017-12-24 09:33:36 +00:00
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << "." << (settings.hilite ? hilite_none : "");
|
2019-06-16 22:51:09 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2017-12-24 09:33:36 +00:00
|
|
|
written = true;
|
2019-06-16 22:42:06 +00:00
|
|
|
|
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2017-12-24 09:33:36 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && 0 == strcmp(name.c_str(), "lambda"))
|
|
|
|
{
|
|
|
|
/// Special case: one-element tuple in lhs of lambda is printed as its element.
|
|
|
|
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
const auto * first_arg_func = arguments->children[0]->as<ASTFunction>();
|
2017-04-01 07:20:54 +00:00
|
|
|
if (first_arg_func
|
|
|
|
&& first_arg_func->name == "tuple"
|
|
|
|
&& first_arg_func->arguments
|
|
|
|
&& first_arg_func->arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
first_arg_func->arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << " -> " << (settings.hilite ? hilite_none : "");
|
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_need_parens);
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && arguments->children.size() >= 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2017-12-09 20:56:53 +00:00
|
|
|
"and", " AND ",
|
|
|
|
"or", " OR ",
|
2017-04-01 07:20:54 +00:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
|
|
|
if (0 == strcmp(name.c_str(), func[0]))
|
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
}
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-09 20:56:53 +00:00
|
|
|
if (!written && 0 == strcmp(name.c_str(), "array"))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ']' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && arguments->children.size() >= 2 && 0 == strcmp(name.c_str(), "tuple"))
|
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '(' << (settings.hilite ? hilite_none : "");
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ')' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!written)
|
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name;
|
|
|
|
|
|
|
|
if (parameters)
|
|
|
|
{
|
|
|
|
settings.ostr << '(' << (settings.hilite ? hilite_none : "");
|
|
|
|
parameters->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
|
|
|
|
}
|
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
if ((arguments && !arguments->children.empty()) || !no_empty_args)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(' << (settings.hilite ? hilite_none : "");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
if (arguments)
|
|
|
|
{
|
2019-02-10 19:11:47 +00:00
|
|
|
bool special_hilite_regexp = settings.hilite
|
2020-12-04 02:15:44 +00:00
|
|
|
&& (name == "match" || name == "extract" || name == "extractAll" || name == "replaceRegexpOne"
|
|
|
|
|| name == "replaceRegexpAll");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
|
|
|
for (size_t i = 0, size = arguments->children.size(); i < size; ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
|
|
|
|
bool special_hilite = false;
|
|
|
|
if (i == 1 && special_hilite_regexp)
|
|
|
|
special_hilite = highlightStringLiteralWithMetacharacters(arguments->children[i], settings, "|()^$.[]?*+{:-");
|
|
|
|
|
|
|
|
if (!special_hilite)
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
2020-12-04 02:15:44 +00:00
|
|
|
}
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
if ((arguments && !arguments->children.empty()) || !no_empty_args)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
|
|
|
|
|
|
|
|
settings.ostr << (settings.hilite ? hilite_none : "");
|
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
|
|
|
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|