1
0
mirror of synced 2024-11-12 10:10:53 +01:00

Implemented union support into the pattern language

This commit is contained in:
WerWolv 2020-11-20 21:29:28 +01:00
parent e3cb078306
commit 48296775ae
8 changed files with 186 additions and 3 deletions

View File

@ -14,6 +14,7 @@ namespace hex::lang {
VariableDecl,
TypeDecl,
Struct,
Union,
Enum,
Bitfield,
Scope,
@ -67,6 +68,18 @@ namespace hex::lang {
std::vector<ASTNode*> m_nodes;
};
class ASTNodeUnion : public ASTNode {
public:
explicit ASTNodeUnion(std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Union), m_name(name), m_nodes(nodes) { }
const std::string& getName() const { return this->m_name; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
private:
std::string m_name;
std::vector<ASTNode*> m_nodes;
};
class ASTNodeBitField : public ASTNode {
public:
explicit ASTNodeBitField(std::string name, std::vector<std::pair<std::string, size_t>> fields)

View File

@ -21,6 +21,7 @@ namespace hex::lang {
std::unordered_map<std::string, ASTNode*> m_types;
std::pair<PatternData*, size_t> createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createBitfieldPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);

View File

@ -31,7 +31,7 @@ namespace hex::lang {
class PatternData {
public:
enum class Type { Unsigned, Signed, Float, Character, String, Struct, Array, Enum };
enum class Type { Unsigned, Signed, Float, Character, String, Struct, Union, Array, Enum };
PatternData(Type type, u64 offset, size_t size, const std::string &name, u32 color = 0)
: m_type(type), m_offset(offset), m_size(size), m_color(color), m_name(name) {
@ -358,6 +358,65 @@ namespace hex::lang {
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataUnion : public PatternData {
public:
PatternDataUnion(u64 offset, size_t size, const std::string &name, const std::string &unionName, const std::vector<PatternData*> & members, u32 color = 0)
: PatternData(Type::Union, offset, size, name, color), m_unionName(unionName), m_members(members), m_sortedMembers(members) { }
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaPreview);
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
if (open) {
for (auto &member : this->m_sortedMembers)
member->createEntry(provider);
ImGui::TreePop();
}
}
std::optional<u32> highlightBytes(size_t offset) override{
for (auto &member : this->m_members) {
if (auto color = member->highlightBytes(offset); color.has_value())
return color.value();
}
return { };
}
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
this->m_sortedMembers = this->m_members;
std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](PatternData *left, PatternData *right) {
return PatternData::sortPatternDataTable(sortSpecs, provider, left, right);
});
for (auto &member : this->m_members)
member->sort(sortSpecs, provider);
}
std::string getTypeName() override {
return "union " + this->m_unionName;
}
private:
std::string m_unionName;
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataEnum : public PatternData {
public:
PatternDataEnum(u64 offset, size_t size, const std::string &name, const std::string &enumName, std::vector<std::pair<u64, std::string>> enumValues, u32 color = 0)
@ -414,7 +473,7 @@ namespace hex::lang {
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
ImGui::Text("{ %llx }", value);
if (open) {
u16 bitOffset = 0;

View File

@ -25,6 +25,7 @@ namespace hex::lang {
struct KeywordToken {
enum class Keyword {
Struct,
Union,
Using,
Enum,
Bitfield

View File

@ -75,6 +75,72 @@ namespace hex::lang {
return { new PatternDataStruct(offset, structSize, varDeclNode->getVariableName(), structNode->getName(), members, 0x00FFFFFF), structSize };
}
std::pair<PatternData*, size_t> Evaluator::createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<PatternData*> members;
auto unionNode = static_cast<ASTNodeUnion*>(this->m_types[varDeclNode->getCustomVariableTypeName()]);
if (unionNode == nullptr)
return { nullptr, 0 };
size_t unionSize = 0;
for (const auto &node : unionNode->getNodes()) {
const auto &member = static_cast<ASTNodeVariableDecl*>(node);
const auto typeDeclNode = static_cast<ASTNodeTypeDecl*>(this->m_types[member->getCustomVariableTypeName()]);
if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
} else if (member->getVariableType() == Token::TypeToken::Type::CustomType
&& typeDeclNode != nullptr && typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit
&& member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
}
else if (member->getArraySize() > 1) {
const auto &[pattern, size] = this->createArrayPattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
}
else if (member->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
}
else {
const auto &[pattern, size] = this->createCustomTypePattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
}
}
return { new PatternDataUnion(offset, unionSize, varDeclNode->getVariableName(), unionNode->getName(), members, 0x00FFFFFF), unionSize };
}
std::pair<PatternData*, size_t> Evaluator::createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<std::pair<u64, std::string>> enumValues;
@ -150,6 +216,8 @@ namespace hex::lang {
switch (currType->getType()) {
case ASTNode::Type::Struct:
return this->createStructPattern(varDeclNode, offset);
case ASTNode::Type::Union:
return this->createUnionPattern(varDeclNode, offset);
case ASTNode::Type::Enum:
return this->createEnumPattern(varDeclNode, offset);
case ASTNode::Type::Bitfield:
@ -208,6 +276,12 @@ namespace hex::lang {
this->m_types.emplace(structNode->getName(), structNode);
}
break;
case ASTNode::Type::Union:
{
auto *unionNode = static_cast<ASTNodeUnion*>(node);
this->m_types.emplace(unionNode->getName(), unionNode);
}
break;
case ASTNode::Type::Enum:
{
auto *enumNode = static_cast<ASTNodeEnum*>(node);

View File

@ -135,6 +135,8 @@ namespace hex::lang {
if (identifier == "struct")
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct } });
else if (identifier == "union")
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Union } });
else if (identifier == "using")
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using } });
else if (identifier == "enum")

View File

@ -75,6 +75,30 @@ namespace hex::lang {
return new ASTNodeStruct(structName, nodes);
}
ASTNode* parseUnion(TokenIter &curr) {
const std::string &unionName = curr[-2].identifierToken.identifier;
std::vector<ASTNode*> nodes;
while (!tryConsume(curr, {Token::Type::ScopeClose})) {
if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression}))
nodes.push_back(parseBuiltinVariableDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypeVariableDecl(curr));
else if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseBuiltinArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypeArrayDecl(curr));
else break;
}
if (!tryConsume(curr, {Token::Type::EndOfExpression})) {
for(auto &node : nodes) delete node;
return nullptr;
}
return new ASTNodeUnion(unionName, nodes);
}
ASTNode* parseEnum(TokenIter &curr) {
const std::string &enumName = curr[-4].identifierToken.identifier;
const Token::TypeToken::Type underlyingType = curr[-2].typeToken.type;
@ -183,6 +207,15 @@ namespace hex::lang {
}
program.push_back(structAst);
} else if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Union) {
auto unionAst = parseUnion(curr);
if (unionAst == nullptr) {
for(auto &node : program) delete node;
return { };
}
program.push_back(unionAst);
} else if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Bitfield) {
auto bitfieldAst = parseBitField(curr);

View File

@ -14,7 +14,7 @@ namespace hex {
static TextEditor::LanguageDefinition langDef;
if (!initialized) {
static const char* const keywords[] = {
"using", "struct", "enum", "bitfield"
"using", "struct", "union", "enum", "bitfield"
};
for (auto& k : keywords)
langDef.mKeywords.insert(k);