datetime as first token

This commit is contained in:
jorenchik
2024-10-06 10:18:22 +03:00
parent 22053041bd
commit 28c1841bdc
8 changed files with 91 additions and 60 deletions

View File

@@ -1,4 +1,4 @@
#include "result.h"
#include "parser.h"
Result<std::vector<Question*>> Transpile(std::string fileContent, bool debug);
Result<ParseInfo> Transpile(std::string fileContent, bool isDebug);

View File

@@ -15,7 +15,7 @@ enum class TokenType {
Cooldown,
CooldownStart,
CooldownEnd,
SOF,
StartOfFile,
EndOfFile
};

View File

@@ -45,4 +45,9 @@ struct GroupQuestion : public Question {
std::string ToString() const override;
};
Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens);
struct ParseInfo {
std::vector<Question*> questions;
time_t lastTrainedAt;
};
Result<ParseInfo> ParseQuestions(const std::vector<Token>& tokens);

View File

@@ -344,13 +344,20 @@ void loadMdem() {
std::stringstream buffer;
buffer << file.rdbuf();
content = buffer.str();
auto parseRes = Transpile(content, true);
auto res = Transpile(content, true);
for (auto question: questions) {
delete question;
}
questions.clear();
if (parseRes.error == "") {
questions = parseRes.value;
if (res.error == "") {
time_t trainedAt;
if (res.value.lastTrainedAt == 0) {
trainedAt = 0;
} else {
trainedAt = res.value.lastTrainedAt + 3600 * 2;
}
std::cout << std::format("Last trained at: {}", trainedAt) << std::endl;
questions = res.value.questions;
makePages();
SwitchPage(0);
std::smatch matches;
@@ -359,7 +366,7 @@ void loadMdem() {
QString::fromStdString(std::format("mdem: {}", matches[2].str()))
);
} else {
std::cout << "Compilation error." << std::endl;
std::cout << std::format("Compilation error: {}", res.error) << std::endl;
for (auto mdem: mdems) {
if (mdem->wMdem->isVisible()) {
mdem->wMdem->hide();

View File

@@ -12,7 +12,7 @@ bool debug;
std::chrono::high_resolution_clock::time_point start;
std::chrono::high_resolution_clock::time_point end;
Result<std::vector<Question*>> Transpile(std::string fileContent, bool isDebug) {
Result<ParseInfo> Transpile(std::string fileContent, bool isDebug) {
start = std::chrono::high_resolution_clock::now();
end = std::chrono::high_resolution_clock::now();
debug = isDebug;

View File

@@ -18,6 +18,7 @@ int32_t previousRow;
int32_t previousColumn;
bool textStarted = false;
bool identifierStarted = false;
bool sof;
void trimString(std::string &str, std::string trimChars) {
int padSize = 0;
@@ -261,6 +262,7 @@ std::string Token::ToString(const TokenType* ttype) {
case TokenType::Cooldown: return "cooldown";
case TokenType::CooldownStart: return "start of cooldown";
case TokenType::CooldownEnd: return "end of cooldown";
case TokenType::StartOfFile: return "start of the file";
case TokenType::EndOfFile: return "end of file";
default: return "unrecognized token";
}

View File

@@ -50,7 +50,7 @@ int main(int argc, char* argv[]) {
ShowTime("I/O time");
auto res = Transpile(fileContent, debug);
auto questions = res.value;
auto questions = res.value.questions;
if (res.error.length() > 0) {
std::cout << std::format(
"{} ({}:{})\n",

View File

@@ -1,4 +1,6 @@
#include <cstdio>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
@@ -103,7 +105,8 @@ std::map<TokenType, std::vector<TokenType>> parserAutomata() {
automata[TokenType::CooldownEnd] = {
TokenType::TextFragment
};
automata[TokenType::SOF] = {
automata[TokenType::StartOfFile] = {
TokenType::TextFragment,
TokenType::ElementDashStart,
TokenType::EndOfFile
};
@@ -138,21 +141,29 @@ Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
return {};
}
Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens) {
Result<ParseInfo> ParseQuestions(const std::vector<Token>& tokens) {
auto questions = std::vector<Question*>();
time_t time = 0;
auto makeResult = [&questions, &time](std::string error, Token token) -> Result<ParseInfo> {
return {
{ questions, time },
error,
token.row,
token.column
};
};
if (tokens.size() == 0) {
return {questions, ""};
return makeResult("", Token());
}
auto result = ValidateGrammar(tokens);
if (result.error.length() > 0) {
return {
questions,
return makeResult(
result.error,
result.row,
result.column
};
Token{.row=result.row, .column=result.column}
);
}
std::string section;
@@ -161,39 +172,49 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
if (debug) {
std::cout << "SECTION: Parser output:\n";
}
while (i < tokens.size()) {
if (tokens[i].tokenType == TokenType::ElementDashStart) {
double cooldown;
std::string questionText;
std::vector<QuestionElement> questionElements;
bool isOrderQuestion = false;
bool isGroupQuestion = false;
bool isPlusQuestion = false;
auto isInBounds = [tokens](size_t i) {
return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile;
};
if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) {
std::tm tm = {};
try {
strptime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M", &tm);
} catch (std::exception e) {
return makeResult(
std::format("cannot parse the time - {}", e.what()),
tokens[i]
);
}
time = mktime(&tm);
i++;
}
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;
// Start element parsing & add to the offset.
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
return {
questions,
return makeResult(
"cannot have order modifier ('^') in the question definition",
tokens[i + 1].row,
tokens[i + 1].column
};
tokens[i + 1]
);
}
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
try {
cooldown = std::stod(tokens[i + 2].content);
} catch (std::exception e) {
return {
questions,
return makeResult(
"error parsing cooldown",
tokens[i + 1].row,
tokens[i + 1].column
};
tokens[i + 1]
);
}
questionText = tokens[i + 4].content;
i += 6;
@@ -220,12 +241,10 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
}
if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) {
// Cannot place the identifier on the ordinary element.
return {
questions,
return makeResult(
"Invalid identifier placement",
tokens[i].row,
tokens[i].column
};
tokens[i]
);
}
}
@@ -243,35 +262,32 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
isOrder = true;
isOrderQuestion = true;
if (!isDash) {
return {
questions,
return makeResult(
"order questions can only be used with dashes ('-')",
tokens[i].row,
tokens[i].column
};
tokens[i]
);
}
if (isGroupQuestion) {
return {
questions,
return makeResult(
"question with groups cannot be ordered ('-^' and ':')",
tokens[i].row,
tokens[i].column
};
tokens[i]
);
}
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
return {
questions,
return makeResult(
"cannot have groups in order question('-^' and ':')",
tokens[i].row,
tokens[i].column
};
tokens[i]
);
}
}
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
isGroup = true;
isGroupQuestion = true;
if (!isDash) {
return {questions, "group questions can only be used with dashes ('-')"};
return makeResult(
"group questions can only be used with dashes ('-')",
tokens[i]
);
}
}
@@ -354,17 +370,18 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
}
break;
} else {
return {
questions,
return makeResult(
"Unexpected token encountered",
tokens[i].row,
tokens[i].column
};
tokens[i]
);
}
}
if (debug) {
std::cout << "SECTION END: Parser output:\n";
}
return {questions, ""};
return makeResult(
"",
Token()
);
}