2020-11-10 20:31:04 +00:00
|
|
|
#include "views/view_pattern.hpp"
|
|
|
|
|
2020-11-17 01:31:51 +00:00
|
|
|
#include "lang/preprocessor.hpp"
|
|
|
|
#include "lang/parser.hpp"
|
|
|
|
#include "lang/lexer.hpp"
|
|
|
|
#include "lang/validator.hpp"
|
2020-11-19 10:36:52 +00:00
|
|
|
#include "lang/evaluator.hpp"
|
2020-11-10 20:31:04 +00:00
|
|
|
#include "utils.hpp"
|
|
|
|
|
|
|
|
namespace hex {
|
|
|
|
|
2020-11-20 17:24:59 +00:00
|
|
|
static const TextEditor::LanguageDefinition& PatternLanguage() {
|
|
|
|
static bool initialized = false;
|
|
|
|
static TextEditor::LanguageDefinition langDef;
|
|
|
|
if (!initialized) {
|
|
|
|
static const char* const keywords[] = {
|
2020-11-20 19:26:19 +00:00
|
|
|
"using", "struct", "enum", "bitfield"
|
2020-11-20 17:24:59 +00:00
|
|
|
};
|
|
|
|
for (auto& k : keywords)
|
|
|
|
langDef.mKeywords.insert(k);
|
|
|
|
|
|
|
|
static const char* const builtInTypes[] = {
|
|
|
|
"u8", "u16", "u32", "u64", "u128",
|
|
|
|
"s8", "s16", "s32", "s64", "s128",
|
|
|
|
"float", "double"
|
|
|
|
};
|
|
|
|
for (auto& k : builtInTypes) {
|
|
|
|
TextEditor::Identifier id;
|
|
|
|
id.mDeclaration = "Built-in type";
|
|
|
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
|
|
|
}
|
|
|
|
|
|
|
|
langDef.mTokenize = [](const char * inBegin, const char * inEnd, const char *& outBegin, const char *& outEnd, TextEditor::PaletteIndex & paletteIndex) -> bool {
|
|
|
|
paletteIndex = TextEditor::PaletteIndex::Max;
|
|
|
|
|
|
|
|
while (inBegin < inEnd && isascii(*inBegin) && isblank(*inBegin))
|
|
|
|
inBegin++;
|
|
|
|
|
|
|
|
if (inBegin == inEnd) {
|
|
|
|
outBegin = inEnd;
|
|
|
|
outEnd = inEnd;
|
|
|
|
paletteIndex = TextEditor::PaletteIndex::Default;
|
|
|
|
}
|
|
|
|
else if (TokenizeCStyleIdentifier(inBegin, inEnd, outBegin, outEnd))
|
|
|
|
paletteIndex = TextEditor::PaletteIndex::Identifier;
|
|
|
|
else if (TokenizeCStyleNumber(inBegin, inEnd, outBegin, outEnd))
|
|
|
|
paletteIndex = TextEditor::PaletteIndex::Number;
|
|
|
|
|
|
|
|
return paletteIndex != TextEditor::PaletteIndex::Max;
|
|
|
|
};
|
|
|
|
|
|
|
|
langDef.mCommentStart = "/*";
|
|
|
|
langDef.mCommentEnd = "*/";
|
|
|
|
langDef.mSingleLineComment = "//";
|
|
|
|
|
|
|
|
langDef.mCaseSensitive = true;
|
|
|
|
langDef.mAutoIndentation = true;
|
|
|
|
langDef.mPreprocChar = '#';
|
|
|
|
|
|
|
|
langDef.mName = "Pattern Language";
|
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
}
|
|
|
|
return langDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-19 10:36:52 +00:00
|
|
|
ViewPattern::ViewPattern(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData)
|
2020-11-14 13:42:21 +00:00
|
|
|
: View(), m_dataProvider(dataProvider), m_patternData(patternData) {
|
2020-11-13 13:35:52 +00:00
|
|
|
|
2020-11-20 17:24:59 +00:00
|
|
|
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
|
|
|
|
this->m_textEditor.SetShowWhitespaces(false);
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
2020-11-20 17:24:59 +00:00
|
|
|
|
2020-11-10 20:31:04 +00:00
|
|
|
ViewPattern::~ViewPattern() {
|
2020-11-20 17:24:59 +00:00
|
|
|
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewPattern::createMenu() {
|
|
|
|
if (ImGui::BeginMenu("File")) {
|
|
|
|
if (ImGui::MenuItem("Load pattern...")) {
|
2020-11-17 14:38:24 +00:00
|
|
|
View::doLater([]{ ImGui::OpenPopup("Open Hex Pattern"); });
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2020-11-11 08:22:55 +00:00
|
|
|
if (ImGui::BeginMenu("View")) {
|
2020-11-10 20:31:04 +00:00
|
|
|
ImGui::MenuItem("Pattern View", "", &this->m_windowOpen);
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewPattern::createView() {
|
|
|
|
if (!this->m_windowOpen)
|
|
|
|
return;
|
|
|
|
|
2020-11-11 09:47:02 +00:00
|
|
|
if (ImGui::Begin("Pattern", &this->m_windowOpen, ImGuiWindowFlags_None)) {
|
2020-11-20 17:24:59 +00:00
|
|
|
this->m_textEditor.Render("Pattern");
|
2020-11-20 19:26:19 +00:00
|
|
|
|
|
|
|
if (this->m_textEditor.IsTextChanged()) {
|
|
|
|
this->parsePattern(this->m_textEditor.GetText().data());
|
|
|
|
}
|
2020-11-11 09:47:02 +00:00
|
|
|
}
|
2020-11-10 20:31:04 +00:00
|
|
|
ImGui::End();
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2020-11-17 14:38:24 +00:00
|
|
|
if (this->m_fileBrowser.showFileDialog("Open Hex Pattern", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".hexpat")) {
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2020-11-17 14:38:24 +00:00
|
|
|
FILE *file = fopen(this->m_fileBrowser.selected_path.c_str(), "rb");
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2020-11-13 13:35:52 +00:00
|
|
|
if (file != nullptr) {
|
2020-11-20 17:24:59 +00:00
|
|
|
char *buffer;
|
2020-11-13 13:35:52 +00:00
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
size_t size = ftell(file);
|
|
|
|
rewind(file);
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2020-11-20 17:24:59 +00:00
|
|
|
buffer = new char[size + 1];
|
|
|
|
|
|
|
|
fread(buffer, size, 1, file);
|
|
|
|
buffer[size] = 0x00;
|
2020-11-12 20:20:51 +00:00
|
|
|
|
|
|
|
|
2020-11-13 13:35:52 +00:00
|
|
|
fclose(file);
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2020-11-20 17:24:59 +00:00
|
|
|
this->parsePattern(buffer);
|
|
|
|
this->m_textEditor.SetText(buffer);
|
|
|
|
|
|
|
|
delete[] buffer;
|
2020-11-13 13:35:52 +00:00
|
|
|
}
|
2020-11-12 20:20:51 +00:00
|
|
|
}
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-14 13:42:21 +00:00
|
|
|
void ViewPattern::clearPatternData() {
|
|
|
|
for (auto &data : this->m_patternData)
|
|
|
|
delete data;
|
2020-11-13 11:07:05 +00:00
|
|
|
|
2020-11-14 13:42:21 +00:00
|
|
|
this->m_patternData.clear();
|
2020-11-19 10:36:52 +00:00
|
|
|
lang::PatternData::resetPalette();
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<std::derived_from<lang::ASTNode> T>
|
|
|
|
static std::vector<T*> findNodes(const lang::ASTNode::Type type, const std::vector<lang::ASTNode*> &nodes) {
|
|
|
|
std::vector<T*> result;
|
|
|
|
|
|
|
|
for (const auto & node : nodes)
|
|
|
|
if (node->getType() == type)
|
|
|
|
result.push_back(static_cast<T*>(node));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewPattern::parsePattern(char *buffer) {
|
2020-11-19 10:36:52 +00:00
|
|
|
hex::lang::Preprocessor preprocessor;
|
|
|
|
hex::lang::Lexer lexer;
|
|
|
|
hex::lang::Parser parser;
|
|
|
|
hex::lang::Validator validator;
|
|
|
|
hex::lang::Evaluator evaluator;
|
2020-11-10 20:31:04 +00:00
|
|
|
|
2020-11-14 13:42:21 +00:00
|
|
|
this->clearPatternData();
|
2020-11-14 23:46:18 +00:00
|
|
|
this->postEvent(Events::PatternChanged);
|
2020-11-10 20:31:04 +00:00
|
|
|
|
2020-11-17 01:31:51 +00:00
|
|
|
auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer);
|
|
|
|
if (preprocessingResult.failed())
|
|
|
|
return;
|
2020-11-10 20:31:04 +00:00
|
|
|
|
2020-11-17 01:31:51 +00:00
|
|
|
auto [lexResult, tokens] = lexer.lex(preprocesedCode);
|
2020-11-10 20:31:04 +00:00
|
|
|
if (lexResult.failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto [parseResult, ast] = parser.parse(tokens);
|
|
|
|
if (parseResult.failed()) {
|
|
|
|
return;
|
2020-11-16 21:54:39 +00:00
|
|
|
}
|
|
|
|
|
2020-11-19 10:36:52 +00:00
|
|
|
hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast) delete node; });
|
|
|
|
|
2020-11-16 21:54:39 +00:00
|
|
|
auto validatorResult = validator.validate(ast);
|
|
|
|
if (!validatorResult) {
|
|
|
|
return;
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
|
2020-11-19 10:36:52 +00:00
|
|
|
auto [evaluateResult, patternData] = evaluator.evaluate(ast);
|
|
|
|
if (evaluateResult.failed()) {
|
|
|
|
return;
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
2020-11-19 10:36:52 +00:00
|
|
|
this->m_patternData = patternData;
|
2020-11-10 20:31:04 +00:00
|
|
|
|
2020-11-14 23:46:18 +00:00
|
|
|
this->postEvent(Events::PatternChanged);
|
2020-11-10 20:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|