30Parser::Parser(
const char *scursor,
const char *
const send,
int options)
31 : i(new Impl(scursor, send, options))
44 i->mBuilder = builder;
53const Error &Parser::error()
const
66static inline unsigned long factorForQuantifier(
char ch)
71 return 1024 * 1024 * 1024;
84static inline bool willOverflowULong(
unsigned long result,
unsigned long add)
86 static const auto maxULongByTen = (
unsigned long)(ULONG_MAX / 10.0);
87 return result > maxULongByTen || ULONG_MAX - 10 * result <
add;
98Parser::Impl::Impl(
const char *scursor,
const char *
const send,
int options)
100 , lexer(scursor, send, options)
105bool Parser::Impl::isStringToken()
const
107 return token() == Lexer::QuotedString || token() == Lexer::MultiLineString;
110bool Parser::Impl::isArgumentToken()
const
112 return isStringToken() || token() == Lexer::Number || token() == Lexer::Tag || (token() == Lexer::Special && mTokenValue ==
QLatin1StringView(
"["));
115bool Parser::Impl::obtainToken()
117 while (!mToken && !lexer.atEnd() && !lexer.error()) {
118 mToken = lexer.nextToken(mTokenValue);
125 case Lexer::HashComment:
126 if (scriptBuilder()) {
127 scriptBuilder()->hashComment(tokenValue());
131 case Lexer::BracketComment:
132 if (scriptBuilder()) {
133 scriptBuilder()->bracketComment(tokenValue());
137 case Lexer::LineFeeds:
138 for (
unsigned int i = 0, end = tokenValue().toUInt(); i <
end; ++i) {
139 if (scriptBuilder()) {
142 scriptBuilder()->lineFeed();
150 if (lexer.error() && scriptBuilder()) {
151 scriptBuilder()->error(lexer.error());
153 return !lexer.error();
156bool Parser::Impl::parse()
159 if (!parseCommandList()) {
163 makeUnexpectedTokenError(Error::ExpectedCommand);
166 if (scriptBuilder()) {
167 scriptBuilder()->finished();
172bool Parser::Impl::parseCommandList()
178 if (!obtainToken()) {
181 if (token() == Lexer::None) {
184 if (token() != Lexer::Identifier) {
187 if (!parseCommand()) {
195bool Parser::Impl::parseCommand()
211 if (!obtainToken() || token() != Lexer::Identifier) {
215 if (scriptBuilder()) {
216 scriptBuilder()->commandStart(tokenValue(), lexer.line());
224 if (!obtainToken()) {
229 makeError(Error::MissingSemicolonOrBlock);
233 if (isArgumentToken() && !parseArgumentList()) {
242 if (!obtainToken()) {
247 makeError(Error::MissingSemicolonOrBlock);
251 if (token() == Lexer::Special && tokenValue() ==
QLatin1Char(
'(')) {
252 if (!parseTestList()) {
256 }
else if (token() == Lexer::Identifier) {
267 if (!obtainToken()) {
272 makeError(Error::MissingSemicolonOrBlock);
276 if (token() != Lexer::Special) {
277 makeUnexpectedTokenError(Error::ExpectedBlockOrSemicolon);
288 makeError(Error::MissingSemicolonOrBlock);
292 if (scriptBuilder()) {
293 scriptBuilder()->commandEnd(lexer.line());
298bool Parser::Impl::parseArgumentList()
304 if (!obtainToken()) {
307 if (!isArgumentToken()) {
310 if (!parseArgument()) {
317bool Parser::Impl::parseArgument()
321 if (!obtainToken() || atEnd()) {
325 if (token() == Lexer::Number) {
326 if (!parseNumber()) {
331 }
else if (token() == Lexer::Tag) {
332 if (scriptBuilder()) {
333 scriptBuilder()->taggedArgument(tokenValue());
337 }
else if (isStringToken()) {
338 if (scriptBuilder()) {
339 scriptBuilder()->stringArgument(tokenValue(), token() == Lexer::MultiLineString,
QString());
343 }
else if (token() == Lexer::Special && tokenValue() ==
QLatin1StringView(
"[")) {
344 if (!parseStringList()) {
354bool Parser::Impl::parseTestList()
358 if (!obtainToken() || atEnd()) {
365 if (scriptBuilder()) {
366 scriptBuilder()->testListStart();
372 bool lastWasComma =
true;
374 if (!obtainToken()) {
382 assert(tokenValue().length() == 1);
383 assert(tokenValue().at(0).toLatin1());
384 switch (tokenValue().at(0).toLatin1()) {
388 makeError(Error::ConsecutiveCommasInTestList);
391 if (scriptBuilder()) {
392 scriptBuilder()->testListEnd();
398 makeError(Error::ConsecutiveCommasInTestList);
404 makeError(Error::NonStringInStringList);
409 case Lexer::Identifier:
411 makeError(Error::MissingCommaInTestList);
414 lastWasComma =
false;
423 makeUnexpectedTokenError(Error::NonTestInTestList);
428 makeError(Error::PrematureEndOfTestList);
432bool Parser::Impl::parseTest()
441 if (!obtainToken() || atEnd()) {
445 if (token() != Lexer::Identifier) {
449 if (scriptBuilder()) {
450 scriptBuilder()->testStart(tokenValue());
458 if (!obtainToken()) {
466 if (isArgumentToken() && !parseArgumentList()) {
475 if (!obtainToken()) {
483 if (token() == Lexer::Special && tokenValue() ==
QLatin1Char(
'(')) {
484 if (!parseTestList()) {
488 }
else if (token() == Lexer::Identifier) {
496 if (scriptBuilder()) {
497 scriptBuilder()->testEnd();
502bool Parser::Impl::parseBlock()
507 if (!obtainToken() || atEnd()) {
514 if (scriptBuilder()) {
515 scriptBuilder()->blockStart(lexer.line());
519 if (!obtainToken()) {
524 makeError(Error::PrematureEndOfBlock);
528 if (token() == Lexer::Identifier) {
529 if (!parseCommandList()) {
535 if (!obtainToken()) {
540 makeError(Error::PrematureEndOfBlock);
545 makeError(Error::NonCommandInCommandList);
548 if (scriptBuilder()) {
549 scriptBuilder()->blockEnd(lexer.line());
555bool Parser::Impl::parseStringList()
564 if (!obtainToken() || atEnd()) {
572 if (scriptBuilder()) {
573 scriptBuilder()->stringListArgumentStart();
579 bool lastWasComma =
true;
581 if (!obtainToken()) {
589 assert(tokenValue().length() == 1);
590 switch (tokenValue().at(0).toLatin1()) {
594 makeError(Error::ConsecutiveCommasInStringList);
597 if (scriptBuilder()) {
598 scriptBuilder()->stringListArgumentEnd();
604 makeError(Error::ConsecutiveCommasInStringList);
610 makeError(Error::NonStringInStringList);
615 case Lexer::QuotedString:
616 case Lexer::MultiLineString:
618 makeError(Error::MissingCommaInStringList);
621 lastWasComma =
false;
622 if (scriptBuilder()) {
623 scriptBuilder()->stringListEntry(tokenValue(), token() == Lexer::MultiLineString,
QString());
629 makeError(Error::NonStringInStringList);
634 makeError(Error::PrematureEndOfStringList);
638bool Parser::Impl::parseNumber()
644 if (!obtainToken() || atEnd()) {
648 if (token() != Lexer::Number) {
653 unsigned long result = 0;
656 for (
const int len = s.
length(); i < len && isdigit(s[i]); ++i) {
657 const unsigned long digitValue = s[i] -
'0';
658 if (willOverflowULong(result, digitValue)) {
659 makeError(Error::NumberOutOfRange);
663 result += digitValue;
668 char quantifier =
'\0';
670 assert(i + 1 == s.
length());
672 const unsigned long factor = factorForQuantifier(quantifier);
673 if (result >
double(ULONG_MAX) /
double(factor)) {
674 makeError(Error::NumberOutOfRange);
680 if (scriptBuilder()) {
681 scriptBuilder()->numberArgument(result, quantifier);
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & end()
qsizetype length() const const