mariadb/sql/item_numconvfunc.cc
2025-06-01 13:28:12 +04:00

2291 lines
73 KiB
C++

/*
Copyright (c) 2009, 2025, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
*/
/**
@file
@brief
This file defines all string functions
@warning
Some string functions don't always put and end-null on a String.
(This shouldn't be needed)
*/
#include "mariadb.h" // HAVE_*
#include "sql_priv.h"
/*
It is necessary to include set_var.h instead of item.h because there
are dependencies on include order for set_var.h and item.h. This
will be resolved later.
*/
#include "sql_class.h" // set_var.h: THD
#include "set_var.h"
#include "sql_base.h"
#include "sql_time.h"
#include "des_key_file.h" // st_des_keyschedule, st_des_keyblock
#include "password.h" // my_make_scrambled_password,
// my_make_scrambled_password_323
#include <m_ctype.h>
#include <my_md5.h>
C_MODE_START
#include "../mysys/my_static.h" // For soundex_map
C_MODE_END
#include "sql_show.h" // append_identifier
#include <sql_repl.h>
#include "sql_statistics.h"
#include "strfunc.h"
#include "item_numconvfunc.h"
#include "lex_ident_sys.h"
#include "simple_tokenizer.h"
#include "sql_list.h"
#include "sql_string.h"
#define LIST_CONTAINERS_PROVIDE_EMPTY
#include "simple_parser.h"
#undef LIST_CONTAINERS_PROVIDE_EMPTY
class Format_tokenizer: public Extended_string_tokenizer
{
public:
Format_tokenizer(CHARSET_INFO *cs, const LEX_CSTRING &str)
:Extended_string_tokenizer(cs, str)
{ }
enum class TokenID
{
// Special purpose tokens:
tNULL= 0, // returned if the tokenizer failed to detect a token
// also used if the parser failed to parse a token
tEMPTY= 1, // returned on empty optional constructs in a grammar like:
// rule ::= [ rule1 ]
// when rule1 does not present in the input.
tEOF= 2, // returned when the end of input is reached
// One character tokens
tCOMMA= ',',
tDOLLAR= '$',
tPERIOD= '.',
tB= 'B',
tC= 'C',
tD= 'D',
tG= 'G',
tL= 'L',
tU= 'U',
tV= 'V',
tS= 'S',
// Other tokens, values must be greater than any of the above
tMI= 256,
tFM,
tPR,
tTM,
tTM9,
tTME,
tZEROS,
tNINES,
tXCHAIN,
tEEEE
};
// A helper wrapper for Lex_cstring with convenience methods
class Lex_cstring_ex: public Lex_cstring
{
public:
using Lex_cstring::Lex_cstring;
const char *ptr() const { return str; }
size_t length() const { return Lex_cstring::length; }
const char *end() const
{
return str ? str + Lex_cstring::length : nullptr;
}
static Lex_cstring_ex empty()
{
return empty_clex_str;
}
void print(String *str) const
{
str->append(ptr(), length());
}
};
class Token: public Lex_cstring_ex
{
protected:
TokenID m_id;
public:
Token()
:Lex_cstring_ex(), m_id(TokenID::tNULL)
{ }
Token(const LEX_CSTRING &str, TokenID id)
:Lex_cstring_ex(str), m_id(id)
{ }
TokenID id() const { return m_id; }
static Token empty(const char *pos)
{
return Token(Lex_cstring(pos, pos), TokenID::tEMPTY);
}
static Token empty()
{
return Token(empty_clex_str, TokenID::tEMPTY);
}
operator bool() const
{
return m_id != TokenID::tNULL;
}
};
//protected:
Token get_token(CHARSET_INFO *cs);
};
static inline constexpr
Format_tokenizer::Lex_cstring_ex operator""_Lex_cstring_ex(const char *str, size_t length)
{
return Format_tokenizer::Lex_cstring_ex(str, length);
}
Format_tokenizer::Token
Format_tokenizer::get_token(CHARSET_INFO *cs)
{
if (eof())
return Token(Lex_cstring(m_ptr, m_ptr), TokenID::tEOF);
if (!get_char(','))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tCOMMA);
if (!get_char('$'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tDOLLAR);
if (!get_char('.'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tPERIOD);
if (!get_char('B'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tB);
if (!get_char('C'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tC);
if (!get_char('D'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tD);
if (!get_char('G'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tG);
if (!get_char('L'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tL);
if (!get_char('U'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tU);
if (!get_char('V'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tV);
if (!get_char('S'))
return Token(Lex_cstring(m_ptr - 1, 1), TokenID::tS);
const char *head= m_ptr;
if (head[0] == '0' || head[0] == '9' || head[0] == 'X')
{
for ( ; !get_char(head[0]) ;)
{ }
if (head[0] == '0')
return Token(Lex_cstring(head, m_ptr), TokenID::tZEROS);
if (head[0] == '9')
return Token(Lex_cstring(head, m_ptr), TokenID::tNINES);
if (head[0] == 'X')
return Token(Lex_cstring(head, m_ptr), TokenID::tXCHAIN);
}
if (m_ptr + 2 <= m_end)
{
const LEX_CSTRING str= Lex_cstring(m_ptr, 2);
if ("MI"_Lex_ident_column.streq(str))
return m_ptr+=2, Token(str, TokenID::tMI);
if ("FM"_Lex_ident_column.streq(str))
return m_ptr+=2, Token(str, TokenID::tFM);
if ("PR"_Lex_ident_column.streq(str))
return m_ptr+=2, Token(str, TokenID::tPR);
if ("TM"_Lex_ident_column.streq(str))
{
if (m_ptr + 3 <= m_end)
{
if (m_ptr[2] == '9')
return m_ptr+= 3, Token(Lex_cstring(head, m_ptr), TokenID::tTM9);
if (m_ptr[2]=='E')
return m_ptr+= 3, Token(Lex_cstring(head, m_ptr), TokenID::tTME);
}
return m_ptr+=2, Token(Lex_cstring(head, m_ptr), TokenID::tTM);
}
}
if (m_ptr + 4 <= m_end)
{
const LEX_CSTRING str= Lex_cstring(m_ptr, 4);
if ("EEEE"_Lex_ident_column.streq(str))
return m_ptr+=4, Token(str, TokenID::tEEEE);
}
return Token(Lex_cstring(m_ptr, m_ptr), TokenID::tNULL);
}
class Format_parser: public Format_tokenizer,
public Parser_templates
{
private:
Token m_look_ahead_token;
THD *m_thd;
const char *m_start;
bool m_syntax_error;
bool m_fatal_error;
public:
Format_parser(THD *thd, CHARSET_INFO *cs, const LEX_CSTRING &str)
:Format_tokenizer(cs, str),
m_look_ahead_token(get_token(cs)),
m_thd(thd),
m_start(str.str),
m_syntax_error(false),
m_fatal_error(false)
{ }
bool set_syntax_error()
{
m_syntax_error= true;
return false;
}
bool set_fatal_error()
{
m_fatal_error= true;
return false;
}
// Calculate the line number inside the whole hint
uint lineno(const char *ptr) const
{
DBUG_ASSERT(m_start <= ptr);
DBUG_ASSERT(ptr <= m_end);
uint lineno= 0;
for ( ; ptr >= m_start; ptr--)
{
if (*ptr == '\n')
lineno++;
}
return lineno;
}
uint lineno() const
{
return lineno(m_ptr);
}
TokenID look_ahead_token_id() const
{
return is_error() ? TokenID::tNULL : m_look_ahead_token.id();
}
/*
Return an empty token at the position of the current
look ahead token with a zero length. Used for optional grammar constructs.
For example, if the grammar is "rule ::= ruleA [ruleB] ruleC"
and the input is "A C", then:
- the optional rule "ruleB" will point to the input position "C"
with a zero length
- while the rule "ruleC" will point to the same input position "C"
with a non-zero length
*/
Token empty_token() const
{
return Token::empty(m_look_ahead_token.str);
}
static Token null_token()
{
return Token();
}
/*
Return the current look ahead token and scan the next one
*/
Token shift()
{
DBUG_ASSERT(!is_error());
const Token res= m_look_ahead_token;
m_look_ahead_token= get_token(m_cs);
return res;
}
public:
/*
Return the current look ahead token if it matches the given ID
and scan the next one.
*/
Token token(TokenID id)
{
if (m_look_ahead_token.id() != id || is_error())
return Token();
return shift();
}
Lex_cstring buffer() const
{
return Lex_cstring(m_start, m_end);
}
bool is_error() const
{
return m_syntax_error || m_fatal_error;
}
bool is_syntax_error() const
{
return m_syntax_error;
}
bool is_fatal_error() const
{
return m_fatal_error;
}
void parse_error_at(THD *thd, const char *pos) const
{
const char *msg= ER_THD(thd, ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR);
const Lex_cstring buf= buffer();
const char *bufend= buf.str + buf.length;
DBUG_ASSERT(pos >= buf.str && pos <= bufend);
ErrConvString txt(pos, bufend - pos, thd->variables.character_set_client);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PARSE_ERROR, ER_THD(thd, ER_PARSE_ERROR),
msg, txt.ptr(), 0/*lineno*/);
}
void push_warning_syntax_error(THD *thd, uint start_lineno) const
{
DBUG_ASSERT(m_start <= m_ptr);
DBUG_ASSERT(m_ptr <= m_end);
const char *msg= ER_THD(thd, ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR);
ErrConvString txt(m_look_ahead_token.str,
m_end - m_look_ahead_token.str,
thd->variables.character_set_client);
/*
start_lineno is the line number on which the whole hint started.
Add the line number of the current tokenizer position inside the hint
(in case hints are written in multiple lines).
*/
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PARSE_ERROR, ER_THD(thd, ER_PARSE_ERROR),
msg, txt.ptr(), start_lineno + lineno());
}
// A helper method for debugging
void trace_tokens(CHARSET_INFO *cs, const LEX_CSTRING &fmt) const
{
Format_tokenizer t(cs, fmt);
Format_tokenizer::Token tok;
for (tok= t.get_token(cs) ;
tok && tok.id() != Format_tokenizer::TokenID::tEOF;
tok= t.get_token(cs))
{ }
}
//private:
using Parser= Format_parser; // for a shorter notation
// A common parent class for various containers
class Lex_cstring_container: public Lex_cstring_ex
{
public:
using Lex_cstring_ex::Lex_cstring_ex;
static Lex_cstring_container empty(const Parser &parser)
{
return parser.empty_token();
}
static Lex_cstring_container empty()
{
return Lex_cstring_ex::empty();
}
operator bool() const
{
return Lex_cstring::str != nullptr;
}
/*
Contatenate list elements into a single container.
There must be no any delimiters in between.
*/
bool concat(const Lex_cstring && rhs)
{
if (!ptr())
{
Lex_cstring::operator=(std::move(rhs));
return false;
}
if (rhs.length == 0)
return false;
if (end() != rhs.str)
{
DBUG_ASSERT(0);
return true;
}
Lex_cstring::length+= rhs.length;
return false;
}
// Methods that allow to pass it as a container to LIST.
size_t count() const { return length(); }
bool add(Parser *p, const Lex_cstring && rhs)
{
return concat(std::move(rhs));
}
};
template<class PARSER>
class Simple_container: public Lex_cstring_container
{
using PARENT= Lex_cstring_container;
using SELF= Simple_container;
using PARENT::PARENT;
public:
Simple_container() :PARENT() { }
Simple_container(SELF && rhs) :PARENT(std::move(rhs)) { }
explicit Simple_container(PARENT && rhs) :PARENT(std::move(rhs)) { }
SELF & operator=(SELF && rhs)
{
PARENT::operator=(std::move(rhs));
return *this;
}
static SELF empty(const Parser &p) { return SELF(PARENT::empty(p)); }
static SELF empty() { return SELF(PARENT::empty()); }
Simple_container(PARSER && rhs)
:PARENT(std::move(static_cast<PARENT&&>(rhs)))
{ }
void print(String *str) const
{
str->append(ptr(), length());
}
};
template<class PARENT>
class Simple_container1: public PARENT
{
using SELF= Simple_container1;
using PARENT::PARENT;
public:
using PARENT::operator bool;
Simple_container1() :PARENT() { }
Simple_container1(SELF && rhs) :PARENT(std::move(rhs)) { }
explicit Simple_container1(PARENT && rhs) :PARENT(std::move(rhs)) { }
SELF & operator=(SELF && rhs)
{
PARENT::operator=(std::move(rhs));
return *this;
}
static SELF empty(const Parser &p) { return SELF(PARENT::empty(p)); }
static SELF empty() { return SELF(PARENT::empty()); }
};
template<class PARENT, class A, class B>
class Simple_container2: public PARENT
{
using SELF= Simple_container2;
public:
using PARENT::PARENT;
// Initialization on parse error
Simple_container2()
:PARENT(A(), B())
{ }
// Initialization from its components
Simple_container2(A && rhs)
:PARENT(A(std::move(rhs)),
B(B::empty()))
{ }
Simple_container2(B && rhs)
:PARENT(A(A::empty()),
B(std::move(rhs)))
{ }
// The rest
Simple_container2(SELF && rhs):PARENT(std::move(rhs)) { }
explicit Simple_container2(PARENT && rhs) :PARENT(std::move(rhs)) { }
SELF & operator=(SELF && rhs)
{
A::operator=(std::move(static_cast<A&&>(rhs)));
B::operator=(std::move(static_cast<B&&>(rhs)));
return *this;
}
static SELF empty(const Parser &p)
{
return SELF(PARENT(A::empty(p), B::empty(p)));
}
static SELF empty()
{
return SELF(PARENT(A::empty(), B::empty()));
}
operator bool() const
{
return A::operator bool() && B::operator bool();
}
};
template<class PARENT, class A, class B, class C>
class Simple_container3: public PARENT
{
using SELF= Simple_container3;
public:
using PARENT::PARENT;
// Initialization on parse error
Simple_container3()
:PARENT(A(), B(), C())
{ }
// Initialization from its components
Simple_container3(A && rhs)
:PARENT(A(std::move(rhs)),
B(B::empty()),
C(C::empty()))
{ }
Simple_container3(B && rhs)
:PARENT(A(A::empty()),
B(std::move(rhs)),
C(C::empty()))
{ }
Simple_container3(C && rhs)
:PARENT(A(A::empty()),
B(B::empty()),
C(std::move(rhs)))
{ }
// The rest
Simple_container3(SELF && rhs):PARENT(std::move(rhs)) { }
explicit Simple_container3(PARENT && rhs) :PARENT(std::move(rhs)) { }
SELF & operator=(SELF && rhs)
{
A::operator=(std::move(static_cast<A&&>(rhs)));
B::operator=(std::move(static_cast<B&&>(rhs)));
C::operator=(std::move(static_cast<C&&>(rhs)));
return *this;
}
static SELF empty(const Parser &p)
{
return SELF(PARENT(A::empty(p), B::empty(p), C::empty(p)));
}
static SELF empty()
{
return SELF(PARENT(A::empty(), B::empty(), C::empty()));
}
operator bool() const
{
return A::operator bool() && B::operator bool() && C::operator bool();
}
};
template<class PARENT, class A, class B, class C, class D>
class Simple_container4: public PARENT
{
using SELF= Simple_container4;
public:
using PARENT::PARENT;
// Initialization on parse error
Simple_container4()
:PARENT(A(), B(), C(), D())
{ }
// Initialization from its components
Simple_container4(A && rhs)
:PARENT(A(std::move(rhs)),
B(B::empty()),
C(C::empty()),
D(D::empty()))
{ }
Simple_container4(B && rhs)
:PARENT(A(A::empty()),
B(std::move(rhs)),
C(C::empty()),
D(D::empty()))
{ }
Simple_container4(C && rhs)
:PARENT(A(A::empty()),
B(B::empty()),
C(std::move(rhs)),
D(D::empty()))
{ }
// The rest
Simple_container4(SELF && rhs):PARENT(std::move(rhs)) { }
explicit Simple_container4(PARENT && rhs) :PARENT(std::move(rhs)) { }
SELF & operator=(SELF && rhs)
{
A::operator=(std::move(static_cast<A&&>(rhs)));
B::operator=(std::move(static_cast<B&&>(rhs)));
C::operator=(std::move(static_cast<C&&>(rhs)));
D::operator=(std::move(static_cast<D&&>(rhs)));
return *this;
}
static SELF empty(const Parser &p)
{
return SELF(PARENT(A::empty(p), B::empty(p), C::empty(p), D::empty(p)));
}
static SELF empty()
{
return SELF(PARENT(A::empty(), B::empty(), C::empty(), D::empty()));
}
operator bool() const
{
return A::operator bool() &&
B::operator bool() &&
C::operator bool() &&
D::operator bool();
}
};
/*
Counters for flags '$' and 'B' and group separators '.' and 'G'.
- Currency prefix flags can have flags '$' and 'B' only: 'BC99.9'
- Integer digits can have both flags and group separators: '9,B,9$'
- Fractional digits can have flags '$' and 'B' only: '.9B$9'
*/
class Decimal_flag_counters
{
public:
size_t m_dollar_count;
size_t m_B_count;
size_t m_cG_count; // comma's and G's
Decimal_flag_counters()
:m_dollar_count(0),
m_B_count(0),
m_cG_count(0)
{ }
Decimal_flag_counters(Decimal_flag_counters && rhs)
:m_dollar_count(rhs.m_dollar_count),
m_B_count(rhs.m_B_count),
m_cG_count(rhs.m_cG_count)
{ }
Decimal_flag_counters & operator=(Decimal_flag_counters && rhs)
{
m_dollar_count= rhs.m_dollar_count;
m_B_count= rhs.m_B_count;
m_cG_count= rhs.m_cG_count;
return *this;
}
void join(Decimal_flag_counters && rhs)
{
m_dollar_count+= rhs.m_dollar_count;
m_B_count+= rhs.m_B_count;
m_cG_count+= rhs.m_cG_count;
}
void add(char ch)
{
if (ch == '$')
m_dollar_count++;
if (ch == 'B')
m_B_count++;
if (ch == '.' || ch == 'G')
m_cG_count++;
}
};
/*
The following chains are returned by the tokenizer as a single token:
zeros: '0' [ '0'... ]
nines: '9' [ '9'... ]
xchain: 'X' [ 'X'...]
*/
class Zeros: public TOKEN<Parser, TokenID::tZEROS> { using TOKEN::TOKEN; };
class Nines: public TOKEN<Parser, TokenID::tNINES> { using TOKEN::TOKEN; };
class XChain: public TOKEN<Parser, TokenID::tXCHAIN> { using TOKEN::TOKEN; };
/********** Rules consisting of a single token *****/
/* with their Opt_ variants when needed */
class TokenEOF: public TOKEN<Parser, TokenID::tEOF> { using TOKEN::TOKEN; };
// Inline flag 'B'
class TokenB: public TOKEN<Parser, TokenID::tB> { using TOKEN::TOKEN; };
class Opt_B: public OPT<Parser, TokenB> { using OPT::OPT; };
// Prefix flag 'FM'
class FlagFM: public TOKEN<Parser, TokenID::tFM> { using TOKEN::TOKEN; };
class Opt_FM: public OPT<Parser, FlagFM> { using OPT::OPT; };
class Format_flags_container: public Lex_cstring_container
{ using Lex_cstring_container::Lex_cstring_container; };
// EEEE - scientific modifier
class EEEE: public TOKEN<Parser, TokenID::tEEEE> { using TOKEN::TOKEN; };
class Opt_EEEE: public OPT<Parser, EEEE> { using OPT::OPT; };
using EEEE_container= Simple_container<EEEE>;
// prefix_sign: 'S'
class Prefix_sign: public TOKEN<Parser, TokenID::tS> { using TOKEN::TOKEN; };
using Prefix_sign_container= Simple_container<Prefix_sign>;
/********** Rules consisting of 2 token choices ***/
/* with their Opt_ variants (when needed) */
// decimal_flag: 'B' | '$'
class Decimal_flag_cond: public TokenChoiceCond2<Parser,
TokenID::tB,
TokenID::tDOLLAR>
{ };
// group_separator: ',' | 'G'
class Group_separator_cond: public TokenChoiceCond2<Parser,
TokenID::tCOMMA,
TokenID::tG>
{ };
class Group_separator: public TokenChoice<Parser, Group_separator_cond>
{ using TokenChoice::TokenChoice; };
// zeros_or_nines: zeros | nines
class Zeros_or_nines_cond: public TokenChoiceCond2<Parser,
TokenID::tZEROS,
TokenID::tNINES>
{ };
class Zeros_or_nines: public TokenChoice<Parser, Zeros_or_nines_cond>
{ using TokenChoice::TokenChoice; };
// Rules consisting of 3 token choices with their Opt_ variants (when needed)
// postfix_sign: 'S' | 'MI' | 'PR'
class Postfix_sign_cond: public TokenChoiceCond3<Parser,
TokenID::tS,
TokenID::tMI,
TokenID::tPR>
{ };
class Postfix_sign: public TokenChoice<Parser, Postfix_sign_cond>
{ using TokenChoice::TokenChoice; };
class Opt_postfix_sign: public OPT<Parser, Postfix_sign> { using OPT::OPT; };
// postfix_only_sign: 'MI' | 'PR'
class Postfix_only_sign_cond: public TokenChoiceCond2<Parser,
TokenID::tMI,
TokenID::tPR>
{ };
class Postfix_only_sign: public TokenChoice<Parser, Postfix_only_sign_cond>
{ using TokenChoice::TokenChoice; };
/*
A shared parser for the postfix sign.
Depending on the grammar rule, the postfix sign can be:
- Postfix_only_sign: MI, PR
- Postfix_sign: MI, PR, S (all sign variants)
This class provides parsing for both variants with further
conversion to and indermediate storage - Lex_cstring (the base).
*/
class Postfix_sign_parser: public Lex_cstring
{
using PARENT= Lex_cstring;
public:
Postfix_sign_parser(Postfix_sign && rhs)
:PARENT(std::move(static_cast<PARENT&&>(rhs)))
{ }
Postfix_sign_parser(Postfix_only_sign && rhs)
:PARENT(std::move(static_cast<PARENT&&>(rhs)))
{ }
};
// The final storage for the postfix sign
using Postfix_sign_container= Simple_container<Postfix_sign_parser>;
/*
positional_currency_signature: 'C' | 'L' | 'U'
The position of CLU inside the format is important, hence the name.
Note, the position of the dollar sign is not important, it can be
specified once on any place inside the number.
*/
class Positional_currency_signature_cond: public TokenChoiceCond3<Parser,
TokenID::tC,
TokenID::tL,
TokenID::tU>
{ };
class Positional_currency_signature:
public TokenChoice<Parser,
Positional_currency_signature_cond>
{ using TokenChoice::TokenChoice; };
class Opt_postfix_currency: public OPT<Parser, Positional_currency_signature>
{ using OPT::OPT; };
// prefix_currency_signature: positional_currency_signature
class Prefix_currency_signature: public Positional_currency_signature
{ using Positional_currency_signature::Positional_currency_signature; };
using Prefix_currency_container= Simple_container<Prefix_currency_signature>;
// postfix_currency_signature: positional_currency_signature
class Postfix_currency_signature: public Positional_currency_signature
{ using Positional_currency_signature::Positional_currency_signature; };
using Postfix_currency_container= Simple_container<Postfix_currency_signature>;
// dec_delimiter_currency_signature: positional_currency_signature
class Dec_delimiter_currency_signature: public Positional_currency_signature
{ using Positional_currency_signature::Positional_currency_signature; };
using Dec_delimiter_pDVCLU_container=
Simple_container<Dec_delimiter_currency_signature>;
// format_TM_signature: 'TM' | 'TM9' | 'TME'
class Format_TM_cond: public TokenChoiceCond3<Parser,
TokenID::tTM,
TokenID::tTM9,
TokenID::tTME>
{ };
class Format_TM_signature: public TokenChoice<Parser, Format_TM_cond>
{ using TokenChoice::TokenChoice; };
using Format_TM_container= Simple_container<Format_TM_signature>;
// fraction_pDV_signature: '.' | 'D' | 'V'
class Fraction_pDV_signature_cond: public TokenChoiceCond3<Parser,
TokenID::tPERIOD,
TokenID::tD,
TokenID::tV>
{ };
class Fraction_pDV_signature: public TokenChoice<Parser,
Fraction_pDV_signature_cond>
{ using TokenChoice::TokenChoice; };
// Rules consisting of more complex token choices
// fractional_element: zeros_or_nines | decimal_flag
class Fractional_element_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return Zeros_or_nines_cond::allowed_token_id(id) ||
Decimal_flag_cond::allowed_token_id(id);
}
};
class Fractional_element: public TokenChoice<Parser, Fractional_element_cond>
{ using TokenChoice::TokenChoice; };
// integer_element: fractional_element | group_separator
class Integer_element_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return Fractional_element_cond::allowed_token_id(id) ||
Group_separator_cond::allowed_token_id(id);
}
};
class Integer_element: public TokenChoice<Parser, Integer_element_cond>
{ using TokenChoice::TokenChoice; };
/*
Rules consisting of a LIST of token choices
*/
// currency_prefix_flag: decimal_flag
// currency_prefix_flags: currency_prefix_flag [ currency_prefix_flag...]
class Currency_prefix_flag: public TokenChoice<Parser, Decimal_flag_cond>
{ using TokenChoice::TokenChoice; };
class Currency_prefix_flags_container: public Lex_cstring_container
{
public:
using Lex_cstring_container::Lex_cstring_container;
Decimal_flag_counters prefix_flag_counters() const
{
Decimal_flag_counters tmp;
for (size_t i= 0; i < length(); i++)
tmp.add(ptr()[i]);
return tmp;
}
};
class Currency_prefix_flags: public LIST<Parser,
Currency_prefix_flags_container,
Currency_prefix_flag,
TokenID::tNULL /* not separated */,
1 /* needs at list one element */>
{ using LIST::LIST; };
/*
A container for format digits - elements that can appear in a number body:
- decimal digit placeholders: 0 9
- hex digit placeholders: X
- inline flags: $ B
*/
class Digit_container: public Lex_cstring_container,
public Decimal_flag_counters
{
public:
Digit_container()
{ }
Digit_container(Digit_container && rhs)
:Lex_cstring_container(std::move(rhs)),
Decimal_flag_counters(std::move(rhs))
{ }
Digit_container & operator=(Digit_container && rhs)
{
Lex_cstring::operator=(std::move(rhs));
Decimal_flag_counters::operator=(std::move(rhs));
return *this;
}
static Digit_container empty(const Parser &p)
{
Digit_container tmp;
tmp.Lex_cstring_container::operator=(Lex_cstring_container::empty(p));
return tmp;
}
static Digit_container empty()
{
Digit_container tmp;
tmp.Lex_cstring_container::operator=(Lex_cstring_container::empty());
return tmp;
}
bool check_counters() const
{
return m_dollar_count > 1 || m_B_count > 1;
}
operator bool() const
{
return Lex_cstring_container::operator bool() &&
!check_counters();
}
/*
Hide the inherited contat() to avoid descendants use it
in a mistake instead of join().
*/
bool concat()= delete;
bool join(Digit_container && rhs)
{
Decimal_flag_counters::join(std::move(rhs));
return Lex_cstring_container::concat(std::move(rhs));
}
bool add(Parser *p, const Lex_cstring && rhs) // for LIST
{
DBUG_ASSERT(rhs.length > 0);
Decimal_flag_counters::add(rhs.str[0]);
if (check_counters())
return true;
return Lex_cstring_container::add(p, std::move(rhs));
}
Digit_container(Zeros_or_nines && rhs)
:Lex_cstring_container(std::move(rhs))
{ }
Digit_container(Zeros && rhs)
:Lex_cstring_container(std::move(rhs))
{ }
Digit_container(Nines && rhs)
:Lex_cstring_container(std::move(rhs))
{ }
Digit_container(XChain && rhs)
:Lex_cstring_container(std::move(rhs))
{ }
};
// integer: integer_digit [ integer_digit...]
class Integer_container: public Digit_container
{
public:
using Digit_container::Digit_container;
Integer_container(Integer_container && rhs)
:Digit_container(std::move(rhs))
{ }
explicit Integer_container(Digit_container && rhs)
:Digit_container(std::move(rhs))
{ }
Integer_container & operator=(Integer_container && rhs)
{
Digit_container::operator=(std::move(rhs));
return *this;
}
static Integer_container empty(const Parser &p)
{
return Integer_container(Digit_container::empty(p));
}
static Integer_container empty()
{
return Integer_container(Digit_container::empty());
}
Integer_container(Zeros && zeros, XChain && xchain)
:Digit_container(std::move(zeros))
{
Lex_cstring_container::concat(std::move(xchain));
}
Integer_container(Zeros_or_nines && zn, XChain && xchain)
:Digit_container(std::move(static_cast<Zeros_or_nines&&>(zn)))
{
Lex_cstring_container::concat(std::move(xchain));
}
// Zeros + extra digits
Integer_container(Zeros && head, Integer_container && tail)
:Digit_container(std::move(head))
{
Integer_container::join(std::move(tail));
}
// Nines + extta digits
Integer_container(Nines && head, Integer_container && tail)
:Digit_container(std::move(head))
{
Integer_container::join(std::move(tail));
}
// Zeros_or_nines + extra digits
Integer_container(Zeros_or_nines && head, Integer_container && tail)
:Digit_container(std::move(head))
{
Integer_container::join(std::move(tail));
}
};
/*
A tail of an integer number.
It can start with a group character.
*/
class Integer_tail: public LIST<Parser, Integer_container,
Integer_element,
TokenID::tNULL /*not separated*/,
1 /* needs at least one element*/>
{ using LIST::LIST; };
// fraction_body: fractional_digit [ fractional_digit ... ]
class Fraction_body_container: public Digit_container
{
public:
using Digit_container::Digit_container;
Fraction_body_container(Fraction_body_container && rhs)
:Digit_container(std::move(rhs))
{ }
explicit Fraction_body_container(Digit_container && rhs)
:Digit_container(std::move(rhs))
{ }
Fraction_body_container & operator=(Fraction_body_container && rhs)
{
Digit_container::operator=(std::move(rhs));
return *this;
}
static Fraction_body_container empty(const Parser &p)
{
return Fraction_body_container(Digit_container::empty(p));
}
static Fraction_body_container empty()
{
return Fraction_body_container(Digit_container::empty());
}
};
// The grammar needs only an optional fraction_body
class Opt_fraction_body: public LIST<Parser, Fraction_body_container,
Fractional_element,
TokenID::tNULL /* not separated */,
0 /* optional: no elements ok */>
{ using LIST::LIST; };
/********** Rules related to the fractional part of a number ***/
/*
fraction_pDVCLU: positional_currency [ fraction_body ]
| fraction_pDV_signature [ fraction_body ] [ positional_currency ]
*/
class Fraction_pDV: public AND2<Parser,
Fraction_pDV_signature,
Opt_fraction_body>
{
public:
using AND2::AND2;
static Fraction_pDV empty(const Parser &parser)
{
return Fraction_pDV(Fraction_pDV_signature::empty(parser),
Opt_fraction_body::empty(parser));
}
};
class Opt_fraction_pDV: public OPT<Parser, Fraction_pDV> { using OPT::OPT; };
class Fraction_pDVCLU_1: public AND2<Parser,
Positional_currency_signature,
Opt_fraction_body>
{ using AND2::AND2; };
class Fraction_pDVCLU_2: public AND3<Parser,
Fraction_pDV_signature,
Opt_fraction_body,
Opt_postfix_currency>
{ using AND3::AND3; };
class Fraction_container_base: public Dec_delimiter_pDVCLU_container,
public Fraction_body_container,
public Postfix_currency_container
{
using A= Dec_delimiter_pDVCLU_container;
using B= Fraction_body_container;
using C= Postfix_currency_container;
public:
// Initialization from its components
Fraction_container_base(Dec_delimiter_pDVCLU_container && a,
Fraction_body_container && b,
Postfix_currency_container && c)
:A(std::move(a)),
B(std::move(b)),
C(std::move(c))
{ }
// Initialization from rules
Fraction_container_base(Fraction_pDV && rhs)
:A(std::move(static_cast<Fraction_pDV_signature&&>(rhs))),
B(std::move(static_cast<Fraction_body_container&&>(rhs))),
C(C::empty())
{ }
/*
TODO: Opt_fraction_body can return true while
Fraction_body_container after initialization from it
(from its Opt_fraction_body::Fraction_body_container actually)
can return false.
*/
Fraction_container_base(Fraction_pDVCLU_1 && rhs)
:A(std::move(static_cast<Positional_currency_signature&&>(rhs))),
B(std::move(static_cast<Opt_fraction_body&&>(rhs))),
C(C::empty())
{ }
Fraction_container_base(Fraction_pDVCLU_2 && rhs)
:A(std::move(static_cast<Fraction_pDV_signature&&>(rhs))),
B(std::move(static_cast<Fraction_body_container&&>(rhs))),
C(std::move(static_cast<Opt_postfix_currency&&>(rhs)))
{ }
};
using Fraction_container= Simple_container3<Fraction_container_base,
Dec_delimiter_pDVCLU_container,
Fraction_body_container,
Postfix_currency_container>;
class Fraction_pDVCLU: public OR2C<Parser,
Fraction_container,
Fraction_pDVCLU_1,
Fraction_pDVCLU_2>
{ using OR2C::OR2C; };
class Opt_fraction_pDVCLU: public OPT<Parser, Fraction_pDVCLU>
{ using OPT::OPT; };
/********** Rules related to a decimal number ***/
/*
decimal_tail_pDVCLU: integer_tail [ fraction_pDVCLU ]
| fraction_pDVCLU
*/
class Decimal_tail_pDVCLU_choice1: public AND2<Parser,
Integer_tail,
Opt_fraction_pDVCLU>
{ using AND2::AND2; };
/*
decimal_tail_pDV: integer_tail [ fraction_pDV ]
| fraction_pDV
*/
class Decimal_tail_pDV_choice1: public AND2<Parser,
Integer_tail,
Opt_fraction_pDV>
{ using AND2::AND2; };
class Decimal_tail_container_base: public Integer_container,
public Fraction_container
{
public:
Decimal_tail_container_base(Decimal_tail_container_base && rhs)
:Integer_container(std::move(rhs)),
Fraction_container(std::move(rhs))
{ }
Decimal_tail_container_base(Integer_container && a,
Fraction_container && b)
:Integer_container(std::move(a)),
Fraction_container(std::move(b))
{ }
Decimal_tail_container_base(Decimal_tail_pDVCLU_choice1 && rhs)
:Integer_container(std::move(rhs)),
Fraction_container(std::move(rhs))
{ }
Decimal_tail_container_base(Decimal_tail_pDV_choice1 && rhs)
:Integer_container(std::move(rhs)),
Fraction_container(std::move(rhs))
{ }
Decimal_tail_container_base(Fraction_pDVCLU && rhs)
:Integer_container(Integer_container::empty()),
Fraction_container(std::move(rhs))
{ }
Decimal_tail_container_base(Fraction_pDV && rhs)
:Integer_container(Integer_container::empty()),
Fraction_container(std::move(rhs))
{ }
};
using Decimal_tail_container=
Simple_container2<Decimal_tail_container_base,
Integer_container,
Fraction_container>;
class Decimal_tail_pDVCLU: public OR2C<Parser,
Decimal_tail_container,
Decimal_tail_pDVCLU_choice1,
Fraction_pDVCLU>
{ using OR2C::OR2C; };
class Decimal_tail_pDV: public OR2C<Parser,
Decimal_tail_container,
Decimal_tail_pDV_choice1,
Fraction_pDV>
{ using OR2C::OR2C; };
class Decimal_container_base: public Decimal_tail_container
{
using PARENT= Decimal_tail_container;
public:
using PARENT::PARENT;
Decimal_container_base(XChain && rhs)
:Decimal_tail_container(std::move(rhs), Fraction_container::empty())
{ }
Decimal_container_base(Zeros && head, Decimal_tail_container_base && tail)
:Decimal_tail_container(
Integer_container(std::move(head),
std::move(static_cast<Integer_container&&>(tail))),
std::move(static_cast<Fraction_container&&>(tail)))
{ }
Decimal_container_base(Nines && head, Decimal_tail_container_base && tail)
:Decimal_tail_container(
Integer_container(std::move(head),
std::move(static_cast<Integer_container&&>(tail))),
std::move(static_cast<Fraction_container&&>(tail)))
{ }
Decimal_container_base(Zeros_or_nines && head,
Decimal_tail_container_base && tail)
:Decimal_tail_container(
Integer_container(std::move(head),
std::move(static_cast<Integer_container&&>(tail))),
std::move(static_cast<Fraction_container&&>(tail)))
{ }
};
using Decimal_container= Simple_container1<Decimal_container_base>;
/********** Rules related to an approximate number (scientific notation) ***/
/*
approximate_tail_pDVCLU: decimal_tail_pDVCLU [ EEEE ]
| EEEE
*/
class Decimal_tail_pDVCLU_Opt_EEEE: public AND2<Parser,
Decimal_tail_pDVCLU,
Opt_EEEE>
{ using AND2::AND2; };
/*
approximate_tail_pDV: decimal_tail_pDV [ EEEE ]
| EEEE
*/
class Decimal_tail_pDV_Opt_EEEE: public AND2<Parser,
Decimal_tail_pDV,
Opt_EEEE>
{ using AND2::AND2; };
/*
Approximate tail:
Its integer part can start with a group character.
*/
class Approximate_tail_container_base: public Decimal_tail_container,
public EEEE_container
{
public:
// Initialization from itself and its components
Approximate_tail_container_base(Approximate_tail_container_base && rhs)
:Decimal_tail_container(std::move(rhs)),
EEEE_container(std::move(rhs))
{ }
Approximate_tail_container_base(Decimal_tail_container && a,
EEEE_container && b)
:Decimal_tail_container(std::move(a)),
EEEE_container(std::move(b))
{ }
// Initialization from rules
Approximate_tail_container_base(EEEE && rhs)
:Decimal_tail_container(Decimal_tail_container::empty()),
EEEE_container(std::move(rhs))
{ }
Approximate_tail_container_base(Decimal_tail_pDVCLU_Opt_EEEE && rhs)
:Decimal_tail_container(std::move(static_cast<Decimal_tail_pDVCLU&&>(rhs))),
EEEE_container(std::move(static_cast<EEEE&&>(rhs)))
{ }
Approximate_tail_container_base(Decimal_tail_pDV_Opt_EEEE && rhs)
:Decimal_tail_container(std::move(static_cast<Decimal_tail_pDV&&>(rhs))),
EEEE_container(std::move(static_cast<EEEE&&>(rhs)))
{ }
// Strange rules
Approximate_tail_container_base(XChain && rhs)
:Decimal_tail_container(std::move(rhs)),
EEEE_container(EEEE_container::empty())
{ }
Approximate_tail_container_base(Fraction_pDV && rhs)
:Decimal_tail_container(std::move(rhs)),
EEEE_container(EEEE_container::empty())
{ }
Approximate_tail_container_base(Fraction_pDVCLU && rhs)
:Decimal_tail_container(std::move(rhs)),
EEEE_container(EEEE_container::empty())
{ }
Approximate_tail_container_base(Zeros && head,
Approximate_tail_container_base && tail)
:Decimal_tail_container(
//Integer_container(std::move(head),std::move(tail)),
std::move(head),
std::move(tail)),
EEEE_container(std::move(tail))
{ }
};
using Approximate_tail_container=
Simple_container2<Approximate_tail_container_base,
Decimal_tail_container,
EEEE_container>;
class Approximate_tail_pDVCLU: public OR2C<Parser,
Approximate_tail_container,
Decimal_tail_pDVCLU_Opt_EEEE,
Opt_EEEE>
{ using OR2C::OR2C; };
class Opt_approximate_tail_pDVCLU: public OPT<Parser, Approximate_tail_pDVCLU>
{ using OPT::OPT; };
class Nines_Opt_approximate_tail_pDVCLU:
public AND2<Parser,
Zeros_or_nines,
Opt_approximate_tail_pDVCLU>
{ using AND2::AND2; };
class Zeros_or_nines_Opt_approximate_tail_pDVCLU:
public AND2<Parser,
Zeros_or_nines,
Opt_approximate_tail_pDVCLU>
{ using AND2::AND2; };
class Approximate_tail_pDV: public OR2C<Parser,
Approximate_tail_container,
Decimal_tail_pDV_Opt_EEEE,
Opt_EEEE>
{ using OR2C::OR2C; };
class Opt_approximate_tail_pDV: public OPT<Parser, Approximate_tail_pDV>
{ using OPT::OPT; };
class Zeros_or_nines_Opt_approximate_tail_pDV:
public AND2<Parser,
Zeros_or_nines,
Opt_approximate_tail_pDV>
{ using AND2::AND2; };
class Zeros_Opt_approximate_tail_pDVCLU:
public AND2<Parser,
Zeros,
Opt_approximate_tail_pDVCLU>
{ using AND2::AND2; };
/*
A container for a well formed approximate number.
Its integer part starts with a valid character such as a digit.
It cannot start with a group character.
*/
class Approximate_container_base: public Approximate_tail_container
{
using PARENT= Approximate_tail_container;
using SELF= Approximate_container_base;
public:
using PARENT::PARENT;
Approximate_container_base(EEEE && rhs)
:PARENT(Decimal_container(Decimal_container::empty()),
EEEE_container(std::move(rhs)))
{ }
Approximate_container_base(EEEE_container && rhs)
:PARENT(Decimal_container(Decimal_container::empty()),
EEEE_container(std::move(rhs)))
{ }
Approximate_container_base(XChain && rhs)
:PARENT(Decimal_container(std::move(rhs)),
EEEE_container::empty())
{ }
Approximate_container_base(Fraction_container && rhs)
:PARENT(Decimal_container(std::move(rhs)),
EEEE_container::empty())
{ }
Approximate_container_base(Fraction_pDV &&rhs)
:PARENT(Decimal_container(std::move(rhs)),
EEEE_container::empty())
{ }
Approximate_container_base(Fraction_container && frac, EEEE && eeee)
:PARENT(Decimal_container(std::move(frac)),
EEEE(std::move(eeee)))
{ }
// Stating with "Zeros"
Approximate_container_base(Zeros && head, Approximate_tail_container && tail)
:PARENT(
Decimal_container(std::move(head),
std::move(static_cast<Decimal_tail_container&&>(tail))),
EEEE_container(std::move(static_cast<EEEE_container&&>(tail))))
{ }
Approximate_container_base(Zeros && head, Approximate_container_base && tail)
:PARENT(
Decimal_container(std::move(head),
std::move(static_cast<Decimal_tail_container&&>(tail))),
EEEE_container(std::move(static_cast<EEEE_container&&>(tail))))
{ }
Approximate_container_base(Zeros_Opt_approximate_tail_pDVCLU && rhs)
:PARENT(
Decimal_container(std::move(static_cast<Zeros &&>(rhs)),
std::move(static_cast<Decimal_tail_container &&>(rhs))),
EEEE_container(std::move(static_cast<EEEE_container&&>(rhs))))
{ }
// Starting with "Nines"
Approximate_container_base(Nines_Opt_approximate_tail_pDVCLU && rhs)
:PARENT(
Decimal_container(std::move(static_cast<Nines &&>(rhs)),
std::move(static_cast<Decimal_tail_container &&>(rhs))),
EEEE_container(std::move(static_cast<EEEE_container&&>(rhs))))
{ }
Approximate_container_base(Nines && head, Approximate_tail_container && tail)
:PARENT(
Decimal_container(std::move(head),
std::move(static_cast<Decimal_tail_container&&>(tail))),
EEEE_container(std::move(static_cast<EEEE_container&&>(tail))))
{ }
// Starting with "Zeros_or_Nines"
Approximate_container_base(Zeros_or_nines_Opt_approximate_tail_pDVCLU && rhs)
:PARENT(
Decimal_container(std::move(static_cast<Zeros_or_nines &&>(rhs)),
std::move(static_cast<Decimal_tail_container &&>(rhs))),
EEEE_container(std::move(static_cast<EEEE_container&&>(rhs))))
{ }
Approximate_container_base(Zeros_or_nines_Opt_approximate_tail_pDV && rhs)
:PARENT(
Decimal_container(std::move(static_cast<Zeros_or_nines &&>(rhs)),
std::move(static_cast<Decimal_tail_container &&>(rhs))),
EEEE_container(std::move(static_cast<EEEE_container&&>(rhs))))
{ }
Approximate_container_base(Zeros_or_nines && head,
Approximate_tail_container && tail)
:PARENT(
Decimal_container(std::move(head),
std::move(static_cast<Decimal_tail_container&&>(tail))),
EEEE_container(std::move(static_cast<EEEE_container&&>(tail))))
{ }
};
using Approximate_container= Simple_container1<Approximate_container_base>;
/*
approximate_pDVCLU: zero_or_nines [ approximate_tail_pDVCLU ]
| fraction_pDVCLU
*/
class Approximate_pDVCLU: public OR2C<Parser,
Approximate_container,
Zeros_or_nines_Opt_approximate_tail_pDVCLU,
Fraction_pDVCLU>
{ using OR2C::OR2C; };
class Opt_approximate_pDVCLU: public OPT<Parser, Approximate_pDVCLU>
{ using OPT::OPT; };
/*
approximate_pDV: zero_or_nines [ approximate_tail_pDV ]
| fraction_pDV
*/
class Approximate_pDV: public OR2C<Parser,
Approximate_container,
Zeros_or_nines_Opt_approximate_tail_pDV,
Fraction_pDV>
{ using OR2C::OR2C; };
class Opt_approximate_pDV: public OPT<Parser, Approximate_pDV>
{ using OPT::OPT; };
/********** Rules related to a number with a prefix currency signature ***/
/*
left_currency: positional_currency_signature approximate_pDV
| positional_currency_signature 'B' approximate_pDV
*/
class B_Opt_Approximate_pDV: public AND2<Parser, TokenB, Opt_approximate_pDV>
{ using AND2::AND2; };
class Left_currency_tail_container_base:
public Currency_prefix_flags_container,
public Approximate_container
{
using A= Currency_prefix_flags_container;
using B= Approximate_container;
public:
// Initialization from its components
Left_currency_tail_container_base(A && a, B && b)
:A(std::move(a)),
B(std::move(b))
{ }
// Initialization from rules
Left_currency_tail_container_base(Fraction_pDV && rhs)
:Currency_prefix_flags_container(Currency_prefix_flags_container::empty()),
Approximate_container(Fraction_container(std::move(rhs)),
EEEE(EEEE::empty()))
{ }
Left_currency_tail_container_base(B_Opt_Approximate_pDV && rhs)
:Currency_prefix_flags_container(std::move(static_cast<TokenB&&>(rhs))),
Approximate_container(std::move(static_cast<Approximate_container&&>(rhs)))
{ }
Left_currency_tail_container_base(
Zeros_or_nines_Opt_approximate_tail_pDV && rhs)
:Currency_prefix_flags_container(std::move(static_cast<Token&&>(rhs))),
Approximate_container(std::move(rhs))
{ }
};
using Left_currency_tail_container=
Simple_container2<Left_currency_tail_container_base,
Currency_prefix_flags_container,
Approximate_container>;
class Left_currency_tail: public OR3C<Parser,
Left_currency_tail_container,
B_Opt_Approximate_pDV,
Zeros_or_nines_Opt_approximate_tail_pDV,
Fraction_pDV>
{ using OR3C::OR3C; };
class Opt_Left_currency_tail: public OPT<Parser, Left_currency_tail>
{
using OPT::OPT;
};
class Left_currency: public AND2<Parser,
Positional_currency_signature,
Opt_Left_currency_tail>
{ using AND2::AND2; };
/*
TODO: modified grammar: added [ 'EEEE' ]
unsigned_currency1:
nines [ approximate_tail_pDVCLU ]
| decimal_flags [ approximate_pDVCLU ]
| left_currency
| fraction_pDV [EEEE] [ positional_currency ]
*/
class Decimal_flags_Opt_approximate_pDVCLU:
public AND2<Parser,
Currency_prefix_flags,
Opt_approximate_pDVCLU>
{ using AND2::AND2; };
/*
TODO: fixed grammar here: added EEEE
< | fraction_pDV [ positional_currency ] -- #4
> | fraction_pDV [EEEE] [ positional_currency ] -- #4
*/
class Fraction_pDV_Opt_EEEE_Opt_postfix_currency:
public AND3<Parser,
Fraction_pDV,
Opt_EEEE,
Opt_postfix_currency>
{ using AND3::AND3; };
class Unsigned_currency_container_base:
public Prefix_currency_container,
public Currency_prefix_flags_container,
public Approximate_container
{
using A= Prefix_currency_container;
using B= Currency_prefix_flags_container;
using C= Approximate_container;
public:
// Initializing from its componenents
Unsigned_currency_container_base(A && a, B && b, C && c)
:A(std::move(a)),
B(std::move(b)),
C(std::move(c))
{ }
// Initializing from rules
Unsigned_currency_container_base(Nines_Opt_approximate_tail_pDVCLU &&rhs)
:A(A::empty()),
B(B::empty()),
C(Approximate_container(std::move(rhs)))
{ }
Unsigned_currency_container_base(Decimal_flags_Opt_approximate_pDVCLU &&rhs)
:A(Prefix_currency_container::empty()),
B(std::move(static_cast<Currency_prefix_flags&&>(rhs))),
C(std::move(static_cast<Approximate_container&&>(rhs)))
{ }
Unsigned_currency_container_base(Left_currency &&rhs)
:A(std::move(static_cast<Positional_currency_signature&&>(rhs))),
B(std::move(static_cast<Currency_prefix_flags_container&&>(rhs))),
C(std::move(static_cast<Approximate_container&&>(rhs)))
{ }
Unsigned_currency_container_base(
Fraction_pDV_Opt_EEEE_Opt_postfix_currency &&rhs)
:A(Positional_currency_signature::empty()),
B(Currency_prefix_flags_container::empty()),
C(Fraction_container(
std::move(static_cast<Fraction_pDV_signature&&>(rhs)),
std::move(static_cast<Opt_fraction_body&&>(rhs)),
std::move(static_cast<Opt_postfix_currency&&>(rhs))),
std::move(static_cast<EEEE&&>(rhs)))
{ }
Unsigned_currency_container_base(Zeros_Opt_approximate_tail_pDVCLU && rhs)
:A(A::empty()),
B(B::empty()),
C(Approximate_container(std::move(rhs)))
{ }
};
using Unsigned_currency_container=
Simple_container3<Unsigned_currency_container_base,
Prefix_currency_container,
Currency_prefix_flags_container,
Approximate_container>;
class Unsigned_currency1: public OR4C<Parser,
Unsigned_currency_container,
Nines_Opt_approximate_tail_pDVCLU,
Decimal_flags_Opt_approximate_pDVCLU,
Left_currency,
Fraction_pDV_Opt_EEEE_Opt_postfix_currency>
{ using OR4C::OR4C; };
/********** Format without a postfix sign ***/
/*
currency_without_postfix_sign: zeros [ approximate_tail_pDVCLU ]
| unsigned_currency1
*/
class Currency_without_postfix_sign:
public OR2C<Parser,
Unsigned_currency_container,
Zeros_Opt_approximate_tail_pDVCLU,
Unsigned_currency1>
{ using OR2C::OR2C; };
class Opt_currency_without_postfix_sign:
public OPT<Parser,
Currency_without_postfix_sign>
{ using OPT::OPT; };
/*
unsigned_format: currency_without_postfix_sign
| format_TM_signature
*/
class Unsigned_format_container_base: public Unsigned_currency_container,
public Format_TM_container
{
using A= Unsigned_currency_container;
using B= Format_TM_container;
public:
// Initializing from its componenet
Unsigned_format_container_base(A && a, B && b)
:A(std::move(a)), B(std::move(b))
{ }
// Initilizing from rules
Unsigned_format_container_base(Currency_without_postfix_sign && rhs)
:A(std::move(rhs)), B(B::empty())
{ }
Unsigned_format_container_base(Format_TM_signature && rhs)
:A(A::empty()), B(std::move(rhs))
{ }
};
using Unsigned_format_container=
Simple_container2<Unsigned_format_container_base,
Unsigned_currency_container,
Format_TM_container>;
class Unsigned_format: public OR2C<Parser,
Unsigned_format_container,
Currency_without_postfix_sign,
Format_TM_signature>
{ using OR2C::OR2C; };
class Opt_unsigned_format: public OPT<Parser, Unsigned_format>
{ using OPT::OPT; };
/********** Format with a postfix sign ***/
/*
currency0_with_postfix_sign:
zeros xchain
| zeros [ approximate_tail_pDVCLU ] [ postfix_sign ]
currency_with_postfix_sign: xchain
| currency0_with_postfix_sign
| unsigned_currency1 [ postfix_sign ]
| postfix_only_sign
Rewriting branches #2a and #3b as:
zeros [ zeros_tail ]
zeros_tail: xchain
| approximate_tail_pDVCLU [ postfix_sign ]
| postfix_sign
*/
class Approximate_tail_pDVCLU_Opt_postfix_sign:
public AND2<Parser,
Approximate_tail_pDVCLU,
Opt_postfix_sign>
{ using AND2::AND2; };
class Approximate_with_postfix_sign_tail_container_base:
public Approximate_tail_container,
public Postfix_sign_container
{
using A= Approximate_tail_container;
using B= Postfix_sign_container;
public:
Approximate_with_postfix_sign_tail_container_base()
:A(Approximate_container::empty()),
B(Postfix_sign::empty())
{ }
// Initialization from its componebts
Approximate_with_postfix_sign_tail_container_base(
Approximate_tail_container &&a,
Postfix_sign_container && b)
:A(std::move(a)),
B(std::move(b))
{ }
// Initialization from rules
Approximate_with_postfix_sign_tail_container_base(XChain && rhs)
:A(Decimal_tail_container(Integer_container(std::move(rhs)))),
B(Postfix_sign::empty())
{ }
Approximate_with_postfix_sign_tail_container_base(
Approximate_tail_pDVCLU_Opt_postfix_sign &&rhs)
:A(std::move(static_cast<Approximate_tail_container&&>(rhs))),
B(std::move(static_cast<Postfix_sign&&>(rhs)))
{ }
Approximate_with_postfix_sign_tail_container_base(Postfix_sign && rhs)
:A(Approximate_container::empty()),
B(std::move(rhs))
{ }
};
using Approximate_with_postfix_sign_tail_container=
Simple_container2<Approximate_with_postfix_sign_tail_container_base,
Approximate_tail_container,
Postfix_sign_container>;
class Currency0_with_postfix_sign_tail:
public OR3C<Parser,
Approximate_with_postfix_sign_tail_container,
XChain,
Approximate_tail_pDVCLU_Opt_postfix_sign,
Opt_postfix_sign>
{ using OR3C::OR3C; };
class Opt_currency_with_postfix_sign_zeros_tail:
public OPT<Parser,
Currency0_with_postfix_sign_tail>
{ using OPT::OPT; };
class Currency0_with_postfix_sign:
public AND2<Parser,
Zeros,
Currency0_with_postfix_sign_tail>
{ using AND2::AND2; };
class Unsigned_currency1_Opt_Postfix_sign: public AND2<Parser,
Unsigned_currency1,
Opt_postfix_sign>
{ using AND2::AND2; };
class Currency_with_postfix_sign_container_base:
public Unsigned_currency_container,
public Postfix_sign_container
{
using A= Unsigned_currency_container;
using B= Postfix_sign_container;
public:
// Initialization from its components
Currency_with_postfix_sign_container_base(A && a, B && b)
:A(std::move(a)),
B(std::move(b))
{ }
// Initialization from rules
Currency_with_postfix_sign_container_base(XChain && rhs)
:A(Approximate_container(
Decimal_container(Integer_container(std::move(rhs))),
EEEE_container(EEEE_container::empty()))),
B(Postfix_sign_container::empty())
{ }
Currency_with_postfix_sign_container_base(
Currency0_with_postfix_sign && rhs)
:A(Unsigned_currency_container(
Prefix_currency_container::empty(),
Currency_prefix_flags_container(
Currency_prefix_flags_container::empty()),
Approximate_container(
std::move(static_cast<Zeros&&>(rhs)),
std::move(static_cast<Approximate_tail_container&&>(rhs))))),
B(std::move(static_cast<Postfix_sign&&>(rhs)))
{ }
Currency_with_postfix_sign_container_base(
Unsigned_currency1_Opt_Postfix_sign && rhs)
:A(Unsigned_currency_container(std::move(rhs))),
B(std::move(static_cast<Postfix_sign&&>(rhs)))
{ }
Currency_with_postfix_sign_container_base(Postfix_only_sign && rhs)
:A(A::empty()),
B(std::move(rhs))
{ }
bool check(const Parser & parser,
const Decimal_flag_counters & prefix_flag_counters) const
{
//DBUG_ASSERT(Fraction_container::m_cG_count == 0);
// TODO: , and G cannot co-exist!!!
// '$9C' '9$C'
if (prefix_flag_counters.m_dollar_count ||
Integer_container::m_dollar_count ||
Fraction_container::m_dollar_count)
{
if (Dec_delimiter_pDVCLU_container::length())
{
const char *dec= Dec_delimiter_pDVCLU_container::ptr();
if (dec[0] == 'C'|| dec[0] == 'L'|| dec[0] == 'U')
{
parser.parse_error_at(current_thd, dec);
return true;
}
}
// '$.C'
if (Postfix_currency_container::length())
{
parser.parse_error_at(current_thd, Postfix_currency_container::ptr());
return true;
}
}
// 'C0$', 'C$U' 'V$U'
if (Prefix_currency_container::length() &&
(Integer_container::m_dollar_count ||
Fraction_container::m_dollar_count))
{
// TODO: better position
parser.parse_error_at(current_thd, Prefix_currency_container::end());
return true;
}
// '$.$' 'B.B'
if (prefix_flag_counters.m_dollar_count +
Integer_container::m_dollar_count +
Fraction_container::m_dollar_count > 1 ||
prefix_flag_counters.m_B_count +
Integer_container::m_B_count +
Fraction_container::m_B_count > 1)
{
// TODO: better position
parser.parse_error_at(current_thd, parser.buffer().str);
return true;
}
if (Integer_container::length() == 0 && EEEE_container::length() != 0)
{
parser.parse_error_at(current_thd, EEEE_container::ptr());
return true;
}
return false;
}
void print(String *str)
{
str->append("CFl='"_Lex_cstring_ex);
Currency_prefix_flags_container::print(str);
str->append("'"_Lex_cstring_ex);
str->append("LCurr='"_Lex_cstring_ex);
Prefix_currency_container::print(str);
str->append("'"_Lex_cstring_ex);
str->append("Dec='"_Lex_cstring_ex);
Dec_delimiter_pDVCLU_container::print(str);
str->append("'"_Lex_cstring_ex);
str->append("RCurr='"_Lex_cstring_ex);
Postfix_currency_container::print(str);
str->append("'"_Lex_cstring_ex);
str->append("RSign='"_Lex_cstring_ex);
Postfix_sign_container::print(str);
str->append("'"_Lex_cstring_ex);
}
};
using Currency_with_postfix_sign_container=
Simple_container2<Currency_with_postfix_sign_container_base,
Unsigned_currency_container,
Postfix_sign_container>;
class Currency_with_postfix_sign:
public OR4C<Parser,
Currency_with_postfix_sign_container,
XChain,
Currency0_with_postfix_sign,
Unsigned_currency1_Opt_Postfix_sign,
Postfix_only_sign>
{
public:
using OR4C::OR4C;
};
/*
format_FM_tail: currency_with_postfix_sign #1
| 'S' [ unsigned_format ] #2
format: currency_with_postfix_sign #1
| 'FM' [ format_FM_tail ] #2
| 'S' ['FM'] [ unsigned_format ] #3
| postfix_only_sign #4
*/
class Prefix_sign_Opt_unsigned_format: public AND2<Parser,
Prefix_sign,
Opt_unsigned_format>
{ using AND2::AND2; };
class Format_FM_tail_container_base: public Prefix_sign_container,
public Unsigned_format_container,
public Postfix_sign_container
{
using A= Prefix_sign_container;
using B= Unsigned_format_container;
using C= Postfix_sign_container;
public:
// Initialization from its components
Format_FM_tail_container_base(A && a, B && b, C && c)
:A(std::move(a)),
B(std::move(b)),
C(std::move(c))
{ }
// Initializing from rules
Format_FM_tail_container_base(Format_TM_signature &&rhs)
:A(A::empty()),
B(Format_TM_container(std::move(rhs))),
C(C::empty())
{ }
Format_FM_tail_container_base(Currency_with_postfix_sign && rhs)
:A(Prefix_sign_container::empty()),
B(Unsigned_format_container(
static_cast<Unsigned_currency_container&&>(rhs))),
C(std::move(static_cast<Postfix_sign_container&&>(rhs)))
{ }
Format_FM_tail_container_base(Prefix_sign_Opt_unsigned_format && rhs)
:A(std::move(static_cast<Prefix_sign&&>(rhs))),
B(std::move(static_cast<Unsigned_format_container&&>(rhs))),
C(Postfix_sign_container::empty())
{ }
};
using Format_FM_tail_container=
Simple_container3<Format_FM_tail_container_base,
Prefix_sign_container,
Unsigned_format_container,
Postfix_sign_container>;
class Format_FM_tail: public OR3C<Parser,
Format_FM_tail_container,
//TODO: should work w the other order:
Format_TM_signature,
Prefix_sign_Opt_unsigned_format,
Currency_with_postfix_sign>
{ using OR3C::OR3C; };
class Opt_format_FM_tail: public OPT<Parser, Format_FM_tail>
{ using OPT::OPT; };
class Format_FM_xxx: public AND2<Parser, FlagFM, Opt_format_FM_tail>
{ using AND2::AND2; };
class Format_prefix_sign_Opt_FM_Opt_unsigned_format:
public AND3<Parser,
Prefix_sign,
Opt_FM,
Opt_unsigned_format>
{ using AND3::AND3; };
class Format_container_base: public Format_flags_container,
public Prefix_sign_container,
public Currency_with_postfix_sign_container,
public Format_TM_container
{
using A= Format_flags_container;
using B= Prefix_sign_container;
using C= Currency_with_postfix_sign_container;
using D= Format_TM_container;
public:
// Initialization from its components
Format_container_base(A && a, B && b, C && c, D && d)
:A(std::move(a)),
B(std::move(b)),
C(std::move(c)),
D(std::move(d))
{ }
// Initialization from rules
Format_container_base(Format_FM_xxx && rhs)
:A(std::move(static_cast<FlagFM&&>(rhs))),
B(std::move(static_cast<Prefix_sign_container&&>(rhs))),
C(Currency_with_postfix_sign_container(
std::move(static_cast<Unsigned_currency_container&&>(rhs)),
Postfix_sign_container::empty())),
D(std::move(static_cast<Format_TM_container&&>(rhs)))
{ }
Format_container_base(Format_prefix_sign_Opt_FM_Opt_unsigned_format && rhs)
:A(std::move(static_cast<FlagFM&&>(rhs))),
B(std::move(static_cast<Prefix_sign&&>(rhs))),
C(std::move(static_cast<Unsigned_currency_container&&>(rhs)),
Postfix_sign_container::empty()),
D(std::move(static_cast<Format_TM_container&&>(rhs)))
{ }
Format_container_base(Postfix_only_sign && rhs)
:A(Format_flags_container::empty()),
B(Prefix_sign_container::empty()),
C(Currency_with_postfix_sign_container(std::move(rhs))),
D(Format_TM_container::empty())
{ }
Format_container_base(Format_TM_signature && rhs)
:A(Format_flags_container::empty()),
B(Prefix_sign_container::empty()),
C(Currency_with_postfix_sign_container::empty()),
D(Format_TM_container(std::move(rhs)))
{ }
void print(String *str)
{
str->append("FFl='"_Lex_cstring_ex);
Format_flags_container::print(str);
str->append("'"_Lex_cstring_ex);
str->append("LSign='"_Lex_cstring_ex);
Prefix_sign_container::print(str);
str->append("'"_Lex_cstring_ex);
if (Currency_with_postfix_sign_container::operator bool())
Currency_with_postfix_sign_container::print(str);
if (Format_TM_container::operator bool())
{
str->append("TM='"_Lex_cstring_ex);
Format_TM_container::print(str);
str->append("'"_Lex_cstring_ex);
}
}
void print_as_note()
{
StringBuffer<64> tmp;
print(&tmp);
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_NOTE,
ER_UNKNOWN_ERROR,
"%.*s", (int) tmp.length(), tmp.ptr());
}
};
using Format_container=
Simple_container4<Format_container_base,
Format_flags_container,
Prefix_sign_container,
Currency_with_postfix_sign_container,
Format_TM_container>;
public:
class Format: public OR5C<Parser, Format_container,
Currency_with_postfix_sign,
Format_FM_xxx,
Format_prefix_sign_Opt_FM_Opt_unsigned_format,
Format_TM_signature,
Postfix_only_sign>
{
public:
using OR5C::OR5C;
bool check(const Parser & parser) const
{
if (!operator bool())
{
parser.push_warning_syntax_error(current_thd, 0);
return true;
}
const auto prefix_flag_counters= Format_container::prefix_flag_counters();
if (Currency_with_postfix_sign_container::operator bool() &&
Currency_with_postfix_sign_container_base::check(parser,
prefix_flag_counters))
return true;
return false;
}
};
class Opt_format: public OPT<Parser, Format>
{ using OPT::OPT; };
#ifndef DBUG_OFF
// A helper type for debugging, to trace subrules
using Goal2= AND2<Parser, Format_FM_xxx, TokenEOF>;
#endif
public:
// goal: [ format ] EOF
using Goal= AND2<Parser, Opt_format, TokenEOF>;
};
double Item_func_to_number::val_real()
{
StringBuffer<STRING_BUFFER_USUAL_SIZE> buffer0, buffer1;
String *subject= args[0]->val_str(&buffer0);
if ((null_value= !subject))
return 0;
String *fmt= args[1]->val_str(&buffer1);
if ((null_value= !fmt))
return 0;
//Format_parser::Res2 res(&parser);
//if ((null_value= !res))
// return 0;
CHARSET_INFO *cs= args[1]->collation.collation;
Format_parser parser(current_thd, cs, fmt->to_lex_cstring());
Format_parser::Goal res(&parser);
if ((null_value= res.check(parser)))
return 0;
DBUG_EXECUTE_IF("numconv",(res.print_as_note()););
return 1;
}