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 "result.h"
|
||||||
#include "parser.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,
|
Cooldown,
|
||||||
CooldownStart,
|
CooldownStart,
|
||||||
CooldownEnd,
|
CooldownEnd,
|
||||||
SOF,
|
StartOfFile,
|
||||||
EndOfFile
|
EndOfFile
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,4 +45,9 @@ struct GroupQuestion : public Question {
|
|||||||
std::string ToString() const override;
|
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;
|
std::stringstream buffer;
|
||||||
buffer << file.rdbuf();
|
buffer << file.rdbuf();
|
||||||
content = buffer.str();
|
content = buffer.str();
|
||||||
auto parseRes = Transpile(content, true);
|
auto res = Transpile(content, true);
|
||||||
for (auto question: questions) {
|
for (auto question: questions) {
|
||||||
delete question;
|
delete question;
|
||||||
}
|
}
|
||||||
questions.clear();
|
questions.clear();
|
||||||
if (parseRes.error == "") {
|
if (res.error == "") {
|
||||||
questions = parseRes.value;
|
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();
|
makePages();
|
||||||
SwitchPage(0);
|
SwitchPage(0);
|
||||||
std::smatch matches;
|
std::smatch matches;
|
||||||
@@ -359,7 +366,7 @@ void loadMdem() {
|
|||||||
QString::fromStdString(std::format("mdem: {}", matches[2].str()))
|
QString::fromStdString(std::format("mdem: {}", matches[2].str()))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Compilation error." << std::endl;
|
std::cout << std::format("Compilation error: {}", res.error) << std::endl;
|
||||||
for (auto mdem: mdems) {
|
for (auto mdem: mdems) {
|
||||||
if (mdem->wMdem->isVisible()) {
|
if (mdem->wMdem->isVisible()) {
|
||||||
mdem->wMdem->hide();
|
mdem->wMdem->hide();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ bool debug;
|
|||||||
std::chrono::high_resolution_clock::time_point start;
|
std::chrono::high_resolution_clock::time_point start;
|
||||||
std::chrono::high_resolution_clock::time_point end;
|
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();
|
start = std::chrono::high_resolution_clock::now();
|
||||||
end = std::chrono::high_resolution_clock::now();
|
end = std::chrono::high_resolution_clock::now();
|
||||||
debug = isDebug;
|
debug = isDebug;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ int32_t previousRow;
|
|||||||
int32_t previousColumn;
|
int32_t previousColumn;
|
||||||
bool textStarted = false;
|
bool textStarted = false;
|
||||||
bool identifierStarted = false;
|
bool identifierStarted = false;
|
||||||
|
bool sof;
|
||||||
|
|
||||||
void trimString(std::string &str, std::string trimChars) {
|
void trimString(std::string &str, std::string trimChars) {
|
||||||
int padSize = 0;
|
int padSize = 0;
|
||||||
@@ -261,6 +262,7 @@ std::string Token::ToString(const TokenType* ttype) {
|
|||||||
case TokenType::Cooldown: return "cooldown";
|
case TokenType::Cooldown: return "cooldown";
|
||||||
case TokenType::CooldownStart: return "start of cooldown";
|
case TokenType::CooldownStart: return "start of cooldown";
|
||||||
case TokenType::CooldownEnd: return "end of cooldown";
|
case TokenType::CooldownEnd: return "end of cooldown";
|
||||||
|
case TokenType::StartOfFile: return "start of the file";
|
||||||
case TokenType::EndOfFile: return "end of file";
|
case TokenType::EndOfFile: return "end of file";
|
||||||
default: return "unrecognized token";
|
default: return "unrecognized token";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ int main(int argc, char* argv[]) {
|
|||||||
ShowTime("I/O time");
|
ShowTime("I/O time");
|
||||||
|
|
||||||
auto res = Transpile(fileContent, debug);
|
auto res = Transpile(fileContent, debug);
|
||||||
auto questions = res.value;
|
auto questions = res.value.questions;
|
||||||
if (res.error.length() > 0) {
|
if (res.error.length() > 0) {
|
||||||
std::cout << std::format(
|
std::cout << std::format(
|
||||||
"{} ({}:{})\n",
|
"{} ({}:{})\n",
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -103,7 +105,8 @@ std::map<TokenType, std::vector<TokenType>> parserAutomata() {
|
|||||||
automata[TokenType::CooldownEnd] = {
|
automata[TokenType::CooldownEnd] = {
|
||||||
TokenType::TextFragment
|
TokenType::TextFragment
|
||||||
};
|
};
|
||||||
automata[TokenType::SOF] = {
|
automata[TokenType::StartOfFile] = {
|
||||||
|
TokenType::TextFragment,
|
||||||
TokenType::ElementDashStart,
|
TokenType::ElementDashStart,
|
||||||
TokenType::EndOfFile
|
TokenType::EndOfFile
|
||||||
};
|
};
|
||||||
@@ -138,21 +141,29 @@ Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens) {
|
Result<ParseInfo> ParseQuestions(const std::vector<Token>& tokens) {
|
||||||
auto questions = std::vector<Question*>();
|
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) {
|
if (tokens.size() == 0) {
|
||||||
return {questions, ""};
|
return makeResult("", Token());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = ValidateGrammar(tokens);
|
auto result = ValidateGrammar(tokens);
|
||||||
if (result.error.length() > 0) {
|
if (result.error.length() > 0) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
result.error,
|
result.error,
|
||||||
result.row,
|
Token{.row=result.row, .column=result.column}
|
||||||
result.column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string section;
|
std::string section;
|
||||||
@@ -161,39 +172,49 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
|
|||||||
if (debug) {
|
if (debug) {
|
||||||
std::cout << "SECTION: Parser output:\n";
|
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) {
|
auto isInBounds = [tokens](size_t i) {
|
||||||
return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile;
|
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.
|
// Start element parsing & add to the offset.
|
||||||
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
|
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"cannot have order modifier ('^') in the question definition",
|
"cannot have order modifier ('^') in the question definition",
|
||||||
tokens[i + 1].row,
|
tokens[i + 1]
|
||||||
tokens[i + 1].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
|
if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) {
|
||||||
try {
|
try {
|
||||||
cooldown = std::stod(tokens[i + 2].content);
|
cooldown = std::stod(tokens[i + 2].content);
|
||||||
} catch (std::exception e) {
|
} catch (std::exception e) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"error parsing cooldown",
|
"error parsing cooldown",
|
||||||
tokens[i + 1].row,
|
tokens[i + 1]
|
||||||
tokens[i + 1].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
questionText = tokens[i + 4].content;
|
questionText = tokens[i + 4].content;
|
||||||
i += 6;
|
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) {
|
if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) {
|
||||||
// Cannot place the identifier on the ordinary element.
|
// Cannot place the identifier on the ordinary element.
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"Invalid identifier placement",
|
"Invalid identifier placement",
|
||||||
tokens[i].row,
|
tokens[i]
|
||||||
tokens[i].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,35 +262,32 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
|
|||||||
isOrder = true;
|
isOrder = true;
|
||||||
isOrderQuestion = true;
|
isOrderQuestion = true;
|
||||||
if (!isDash) {
|
if (!isDash) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"order questions can only be used with dashes ('-')",
|
"order questions can only be used with dashes ('-')",
|
||||||
tokens[i].row,
|
tokens[i]
|
||||||
tokens[i].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (isGroupQuestion) {
|
if (isGroupQuestion) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"question with groups cannot be ordered ('-^' and ':')",
|
"question with groups cannot be ordered ('-^' and ':')",
|
||||||
tokens[i].row,
|
tokens[i]
|
||||||
tokens[i].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
|
if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"cannot have groups in order question('-^' and ':')",
|
"cannot have groups in order question('-^' and ':')",
|
||||||
tokens[i].row,
|
tokens[i]
|
||||||
tokens[i].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
|
if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) {
|
||||||
isGroup = true;
|
isGroup = true;
|
||||||
isGroupQuestion = true;
|
isGroupQuestion = true;
|
||||||
if (!isDash) {
|
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;
|
break;
|
||||||
} else {
|
} else {
|
||||||
return {
|
return makeResult(
|
||||||
questions,
|
|
||||||
"Unexpected token encountered",
|
"Unexpected token encountered",
|
||||||
tokens[i].row,
|
tokens[i]
|
||||||
tokens[i].column
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
std::cout << "SECTION END: Parser output:\n";
|
std::cout << "SECTION END: Parser output:\n";
|
||||||
}
|
}
|
||||||
return {questions, ""};
|
return makeResult(
|
||||||
|
"",
|
||||||
|
Token()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user