mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
datetime as first token
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -15,7 +15,7 @@ enum class TokenType {
|
||||
Cooldown,
|
||||
CooldownStart,
|
||||
CooldownEnd,
|
||||
SOF,
|
||||
StartOfFile,
|
||||
EndOfFile
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user