stylistic parsing fixes

This commit is contained in:
jorenchik
2025-01-03 19:40:44 +02:00
parent aebd17f79e
commit 0822ae5f0d
2 changed files with 274 additions and 272 deletions

View File

@@ -546,7 +546,6 @@ Mdem* makeMdem() {
// Aizmuguras saturs.
for (size_t i = 0; i < 20; ++i) {
// @Improve: back label pooling
QLabel *elBackText = new QLabel();
mdem->hBack.addWidget(elBackText);
mdem->backLabels.push_back(elBackText);

View File

@@ -75,7 +75,7 @@ void initTransitions() {
* Pārbauda, vai tekstvienību saraksts atbilst valodas
* definētām pieļaujamām pārejām.
* */
Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
Result<NoneType> validateGrammar(const std::vector<Token>& tokens) {
if (!transitions) {
initTransitions();
}
@@ -125,6 +125,9 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
// kļūdas informāciju.
auto makeResult = [&questions, &time](std::string error, Token token)
-> Result<ParseInfo> {
if (debug) {
std::cout << "SECTION END: PARSER:\n";
}
return {
{ questions, time },
error,
@@ -137,7 +140,7 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
if (tokens.size() == 0) {
return makeResult("", Token());
}
auto result = ValidateGrammar(tokens);
auto result = validateGrammar(tokens);
if (result.error.length() > 0) {
return makeResult(
result.error,
@@ -145,8 +148,6 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
);
}
size_t i = 0;
if (debug) {
std::cout << "SECTION: PARSER:\n";
}
@@ -157,6 +158,7 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile;
};
size_t i = 0;
// Sākuma datumu un laiku mēģina nolasīt, ja tāds ir norādīts.
if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) {
@@ -191,288 +193,289 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
// Pamata parsēšana.
while (i < tokens.size()) {
if (tokens[i].tokenType == TokenType::ElementDashStart) {
std::string questionText;
std::vector<QuestionElement> questionElements;
double cooldown;
bool isOrderQuestion = false;
bool isGroupQuestion = false;
bool isPlusQuestion = false;
bool hasGroupEncountered = false;
Token questionStartToken;
switch (tokens[i].tokenType) {
case TokenType::ElementDashStart: {
std::string questionText;
std::vector<QuestionElement> questionElements;
double cooldown;
bool isOrderQuestion = false;
bool isGroupQuestion = false;
bool isPlusQuestion = false;
bool hasGroupEncountered = false;
Token questionStartToken;
// Šajā momentā ir sagaidāms jautājuma sākums - tam nevar būt secības modifikators.
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
return makeResult(
"Nevar izmantot secības modifikatoru ('^') jautājuma sākumā",
tokens[i + 1]);
}
// Piefiksē sākumu, lai varētu sniegt labāku kļūdas
// atrašanās vietu kļūdas gadījumā.
questionStartToken = tokens[i];
// Apstrādā pārtraukumu, ja tāds ir.
bool hasCooldown;
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
try {
auto cooldownContent = tokens[i + 2].content;
// Pārbauda, vai dotais pārtraukums ir viens skaitlis, kas ir:
// - pozitīvs;
// - viens no: vesels skaitlis vai ar punktu atdalīts skaitlis
// ar norādīto vai bez norādītās veselās daļas.
static const std::regex decimalNumExp(
"^\\d*(\\.\\d+)?$",
std::regex_constants::ECMAScript | std::regex_constants::icase
);
if (!std::regex_match(cooldownContent, decimalNumExp)) {
throw std::invalid_argument("Nekorekts pārtraukuma formāts");
}
cooldown = std::stod(cooldownContent);
} catch (std::exception e) {
return makeResult(
"Nekorekts pārtraukums. Pārtraukums ir viens pozitīvs "
"decimāls skaitlis ar punktu vai bez punkta",
tokens[i + 1]
);
}
questionText = tokens[i + 4].content;
hasCooldown = true;
} else {
cooldown = 0;
questionText = tokens[i + 1].content;
hasCooldown = false;
}
int questionStartOffset = hasCooldown ? 5 : 2;
// Pārbauda, vai jautājums ir nobeigts ar korektu simbolu.
if (isInBounds(questionStartOffset) &&
tokens[i + questionStartOffset].tokenType != TokenType::QuestionEnd) {
return makeResult(
"Jautājumu var iesākt tikai ar \">\"",
tokens[i + questionStartOffset]
);
}
i += hasCooldown ? 6 : 3;
// Jautājumu elementu parsēšana.
while (isInBounds(i)) {
// Pārbauda, vai nav sastapts cits jautājuma sākums, un noslēdz, ja tas tā ir.
if (isInBounds(i + 3) && tokens[i].tokenType == TokenType::ElementDashStart) {
// Jautājumam var būt un var nebūt pārtraukums - nosaka vai tas būtu.
size_t offset;
if (tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
offset = tokens[i + 2].tokenType == TokenType::CooldownStart ? 6 : 3;
} else {
offset = tokens[i + 1].tokenType == TokenType::CooldownStart ? 5 : 2;
}
if (isInBounds(i + offset) && tokens[i + offset].tokenType == TokenType::QuestionEnd) {
break;
}
if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) {
return makeResult(
"Jautājuma elementam nevar būt pārtraukums",
tokens[i]
);
}
// Šajā momentā ir sagaidāms jautājuma sākums - tam nevar būt secības modifikators.
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
return makeResult(
"Nevar izmantot secības modifikatoru ('^') jautājuma sākumā",
tokens[i + 1]);
}
// Jautājuma elementa noteikšana un ar to saistītās kļūdas.
bool isDash;
bool isGroup = false;
bool isOrder = false;
// Elementa sākums.
if (tokens[i].tokenType == TokenType::ElementDashStart) {
isDash = true;
} else {
isDash = false;
isPlusQuestion = true;
if (isGroupQuestion) {
return makeResult(
"Jautājumos ar grupām nevar būt secības elementu ('+' and ':')",
tokens[i]
);
}
if (isOrderQuestion) {
return makeResult(
"Secības jautājumos nevar būt izvēles elementu ('-^' and '+')",
tokens[i]
);
}
}
// Piefiksē sākumu, lai varētu sniegt labāku kļūdas
// atrašanās vietu kļūdas gadījumā.
questionStartToken = tokens[i];
// Elementa secības modifikators.
if (isInBounds(i+1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
isOrder = true;
isOrderQuestion = true;
if (!isDash) {
return makeResult(
"Secības jautājumus var izmantot tikai ar svītrām ('-')",
tokens[i]
);
}
if (isGroupQuestion) {
return makeResult(
"Jautājumos ar grupām nevar būt secības elementu ('-^' and ':')",
tokens[i]
);
}
if (isPlusQuestion) {
return makeResult(
"Izvēles jautājumos nevar būt secības elementu ('+' and '-^')",
tokens[i]
);
}
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
return makeResult(
"Secības jautājumā nevar būt grupas ('-^' and ':')",
tokens[i]
);
}
}
// Apstrādā pārtraukumu, ja tāds ir.
bool hasCooldown;
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
try {
auto cooldownContent = tokens[i + 2].content;
// Pārbauda, vai dotais pārtraukums ir viens skaitlis, kas ir:
// - pozitīvs;
// - viens no: vesels skaitlis vai ar punktu atdalīts skaitlis
// ar norādīto vai bez norādītās veselās daļas.
static const std::regex decimalNumExp(
"^\\d*(\\.\\d+)?$",
std::regex_constants::ECMAScript | std::regex_constants::icase
);
if (!std::regex_match(cooldownContent, decimalNumExp)) {
throw std::invalid_argument("Nekorekts pārtraukuma formāts");
}
cooldown = std::stod(cooldownContent);
} catch (std::exception e) {
return makeResult(
"Nekorekts pārtraukums. Pārtraukums ir viens pozitīvs "
"decimāls skaitlis ar punktu vai bez punkta",
tokens[i + 1]
);
}
questionText = tokens[i + 4].content;
hasCooldown = true;
} else {
cooldown = 0;
questionText = tokens[i + 1].content;
hasCooldown = false;
}
// Elementa grupas modifikators.
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
isGroup = true;
isGroupQuestion = true;
if (!isDash) {
return makeResult(
"Grupas jautājumus var definēt tikai ar svītru elementiem ('-')",
tokens[i]
);
}
if (!hasGroupEncountered) {
if (questionElements.size() > 0) {
return makeResult(
"Elementi grupas jautājumā nevar eksistēt bez grupas",
tokens[i]
);
}
}
hasGroupEncountered = true;
}
int questionStartOffset = hasCooldown ? 5 : 2;
// Pārbauda, vai jautājums ir nobeigts ar korektu simbolu.
if (isInBounds(questionStartOffset) &&
tokens[i + questionStartOffset].tokenType != TokenType::QuestionEnd) {
return makeResult(
"Jautājumu var iesākt tikai ar \">\"",
tokens[i + questionStartOffset]
);
}
i += hasCooldown ? 6 : 3;
// Izveido atbilstoša veida jautājuma elementu.
QuestionElement questionElement;
questionElement.isDash = isDash;
questionElement.isGroup = isGroup;
if (isOrder) {
questionElement.content = tokens[i + 2].content;
} else {
questionElement.content = tokens[i + 1].content;
}
questionElements.push_back(questionElement);
// Jautājumu elementu parsēšana.
while (isInBounds(i)) {
// Nākamā elementa atrašanās vieta ir atkarīga no elementu
// veida, kas ir sastapts.
size_t offset = 2;
if (isOrder) {
offset += 1;
}
if (isGroup) {
offset += 1;
}
i += offset;
}
// Pārbauda, vai nav sastapts cits jautājuma sākums, un noslēdz, ja tas tā ir.
if (isInBounds(i + 3) && tokens[i].tokenType == TokenType::ElementDashStart) {
// Izveido jautājuma objektu.
// Fix: else block - jautājums bez elementiem.
if (questionElements.size() > 0) {
if (isGroupQuestion) {
auto *question = new GroupQuestion();
question->cooldown = cooldown;
question->questionText = cleanContent(questionText);
// Jautājumam var būt un var nebūt pārtraukums - nosaka vai tas būtu.
size_t offset;
if (tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
offset = tokens[i + 2].tokenType == TokenType::CooldownStart ? 6 : 3;
} else {
offset = tokens[i + 1].tokenType == TokenType::CooldownStart ? 5 : 2;
}
if (isInBounds(i + offset) && tokens[i + offset].tokenType == TokenType::QuestionEnd) {
break;
}
// Izveido grupas; i - elementu iterators; k - grupu iterators.
int32_t k = -1;
for (size_t i = 0; i < questionElements.size(); ++i) {
auto questionElement = questionElements[i];
if (questionElement.isGroup) {
++k;
auto group = Group();
group.name = cleanContent(questionElement.content);
question->groups.push_back(group);
} else {
if (k >= 0) {
question->groups[k].elements.push_back(
cleanContent(
questionElement.content
)
);
}
}
}
questions.push_back(question);
if (debug) {
std::cout << question->toString() << "\n";
}
} else {
auto *question = new MultiElementQuestion();
question->cooldown = cooldown;
question->questionText = cleanContent(questionText);
if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) {
return makeResult(
"Jautājuma elementam nevar būt pārtraukums",
tokens[i]
);
}
}
// Jautājuma elementa noteikšana un ar to saistītās kļūdas.
bool isDash;
bool isGroup = false;
bool isOrder = false;
// Izveido vairāku elementu jautājumu.
auto existingElements = std::set<std::string>();
for (const auto& elem : questionElements) {
Choice choice;
choice.answer = cleanContent(elem.content);
choice.isCorrect = !elem.isDash;
// Elementa sākums.
if (tokens[i].tokenType == TokenType::ElementDashStart) {
isDash = true;
} else {
isDash = false;
isPlusQuestion = true;
if (isGroupQuestion) {
return makeResult(
"Jautājumos ar grupām nevar būt secības elementu ('+' and ':')",
tokens[i]
);
}
if (isOrderQuestion) {
return makeResult(
"Secības jautājumos nevar būt izvēles elementu ('-^' and '+')",
tokens[i]
);
}
}
// Secības elementiem nedrīkst būt vienādi elementi.
if (isOrderQuestion) {
if (existingElements.contains(choice.answer)) {
return makeResult(
"Secības jautājumi atbildes nedrīkst atkārtoties",
questionStartToken
);
} else {
question->choices.push_back(choice);
existingElements.insert(choice.answer);
}
} else {
question->choices.push_back(choice);
}
}
questions.push_back(question);
// Elementa secības modifikators.
if (isInBounds(i+1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
isOrder = true;
isOrderQuestion = true;
if (!isDash) {
return makeResult(
"Secības jautājumus var izmantot tikai ar svītrām ('-')",
tokens[i]
);
}
if (isGroupQuestion) {
return makeResult(
"Jautājumos ar grupām nevar būt secības elementu ('-^' and ':')",
tokens[i]
);
}
if (isPlusQuestion) {
return makeResult(
"Izvēles jautājumos nevar būt secības elementu ('+' and '-^')",
tokens[i]
);
}
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
return makeResult(
"Secības jautājumā nevar būt grupas ('-^' and ':')",
tokens[i]
);
}
}
// Uzstāda vairāku elementu jautājuma specializēto veidu.
if (isPlusQuestion) {
question->type = MultiElementType::MultiChoice;
} else if (isOrderQuestion) {
question->type = MultiElementType::Order;
} else {
question->type = MultiElementType::Regular;
}
if (debug) {
std::cout << question->toString() << "\n";
}
}
} else {
return makeResult(
"Jautājums nevar būt bez atbildes elementiem",
questionStartToken
);
}
} else if (tokens[i].tokenType == TokenType::EndOfFile) {
if (debug) {
std::cout << "Fails beidzās: EndOfFile\n";
}
break;
} else {
return makeResult(
"Negaidīta tekstvienība",
tokens[i]
);
// Elementa grupas modifikators.
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
isGroup = true;
isGroupQuestion = true;
if (!isDash) {
return makeResult(
"Grupas jautājumus var definēt tikai ar svītru elementiem ('-')",
tokens[i]
);
}
if (!hasGroupEncountered) {
if (questionElements.size() > 0) {
return makeResult(
"Elementi grupas jautājumā nevar eksistēt bez grupas",
tokens[i]
);
}
}
hasGroupEncountered = true;
}
// Izveido atbilstoša veida jautājuma elementu.
QuestionElement questionElement;
questionElement.isDash = isDash;
questionElement.isGroup = isGroup;
if (isOrder) {
questionElement.content = tokens[i + 2].content;
} else {
questionElement.content = tokens[i + 1].content;
}
questionElements.push_back(questionElement);
// Nākamā elementa atrašanās vieta ir atkarīga no elementu
// veida, kas ir sastapts.
size_t offset = 2;
if (isOrder) {
offset += 1;
}
if (isGroup) {
offset += 1;
}
i += offset;
}
if (questionElements.size() > 0) {
// Izveido jautājuma objektu.
if (isGroupQuestion) {
auto *question = new GroupQuestion();
question->cooldown = cooldown;
question->questionText = cleanContent(questionText);
// Izveido grupas; i - elementu iterators; k - grupu iterators.
int32_t k = -1;
for (size_t i = 0; i < questionElements.size(); ++i) {
auto questionElement = questionElements[i];
if (questionElement.isGroup) {
++k;
auto group = Group();
group.name = cleanContent(questionElement.content);
question->groups.push_back(group);
} else {
if (k >= 0) {
question->groups[k].elements.push_back(
cleanContent(
questionElement.content
)
);
}
}
}
questions.push_back(question);
if (debug) {
std::cout << question->toString() << "\n";
}
} else {
auto *question = new MultiElementQuestion();
question->cooldown = cooldown;
question->questionText = cleanContent(questionText);
// Izveido vairāku elementu jautājumu.
auto existingElements = std::set<std::string>();
for (const auto& elem : questionElements) {
Choice choice;
choice.answer = cleanContent(elem.content);
choice.isCorrect = !elem.isDash;
// Secības elementiem nedrīkst būt vienādi elementi.
if (isOrderQuestion) {
if (existingElements.contains(choice.answer)) {
return makeResult(
"Secības jautājumi atbildes nedrīkst atkārtoties",
questionStartToken
);
} else {
question->choices.push_back(choice);
existingElements.insert(choice.answer);
}
} else {
question->choices.push_back(choice);
}
}
questions.push_back(question);
// Uzstāda vairāku elementu jautājuma specializēto veidu.
if (isPlusQuestion) {
question->type = MultiElementType::MultiChoice;
} else if (isOrderQuestion) {
question->type = MultiElementType::Order;
} else {
question->type = MultiElementType::Regular;
}
if (debug) {
std::cout << question->toString() << "\n";
}
}
} else {
return makeResult(
"Jautājums nevar būt bez atbildes elementiem",
questionStartToken
);
}
} break;
case TokenType::EndOfFile: {
return makeResult(
"",
Token()
);
} break;
default: {
return makeResult(
"",
Token()
);
} break;
}
}
if (debug) {
std::cout << "SECTION END: PARSER:\n";
}
return makeResult(
"",
Token()