1
0
mirror of synced 2025-01-30 11:37:32 +01:00

pattern: Improved attribute handling

This commit is contained in:
WerWolv 2022-02-08 17:50:42 +01:00
parent 3539b42c77
commit e918a594f3

View File

@ -97,6 +97,32 @@ namespace hex::pl {
return this->m_attributes; return this->m_attributes;
} }
bool hasAttribute(const std::string &key, bool needsParameter) const {
return std::any_of(this->m_attributes.begin(), this->m_attributes.end(), [&](ASTNodeAttribute *attribute) {
if (attribute->getAttribute() == key) {
if (needsParameter && !attribute->getValue().has_value())
LogConsole::abortEvaluation(hex::format("attribute '{}' expected a parameter"), attribute);
else if (!needsParameter && attribute->getValue().has_value())
LogConsole::abortEvaluation(hex::format("attribute '{}' did not expect a parameter "), attribute);
else
return true;
}
return false;
});
}
[[nodiscard]] std::optional<std::string> getAttributeValue(const std::string &key) const {
auto attribute = std::find_if(this->m_attributes.begin(), this->m_attributes.end(), [&](ASTNodeAttribute *attribute) {
return attribute->getAttribute() == key;
});
if (attribute != this->m_attributes.end())
return (*attribute)->getValue();
else
return std::nullopt;
}
private: private:
std::vector<ASTNodeAttribute *> m_attributes; std::vector<ASTNodeAttribute *> m_attributes;
}; };
@ -692,91 +718,91 @@ namespace hex::pl {
ASTNode *m_postExpression; ASTNode *m_postExpression;
}; };
inline void applyVariableAttributes(Evaluator *evaluator, const Attributable *attributable, PatternData *pattern) { inline void applyVariableAttributes(Evaluator *evaluator, const ASTNode *node, PatternData *pattern) {
auto attributable = dynamic_cast<const Attributable *>(node);
if (attributable == nullptr)
LogConsole::abortEvaluation("attribute cannot be applied here", node);
auto endOffset = evaluator->dataOffset(); auto endOffset = evaluator->dataOffset();
evaluator->dataOffset() = pattern->getOffset(); evaluator->dataOffset() = pattern->getOffset();
ON_SCOPE_EXIT { evaluator->dataOffset() = endOffset; }; ON_SCOPE_EXIT { evaluator->dataOffset() = endOffset; };
for (ASTNodeAttribute *attribute : attributable->getAttributes()) { if (auto value = attributable->getAttributeValue("color"); value) {
auto &name = attribute->getAttribute(); u32 color = strtoul(value->c_str(), nullptr, 16);
auto value = attribute->getValue(); pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8);
}
auto node = reinterpret_cast<const ASTNode *>(attributable); if (auto value = attributable->getAttributeValue("name"); value) {
pattern->setDisplayName(*value);
}
auto requiresValue = [&]() { if (auto value = attributable->getAttributeValue("comment"); value) {
if (!value.has_value()) pattern->setComment(*value);
LogConsole::abortEvaluation(hex::format("used attribute '{}' without providing a value", name), node); }
return true;
};
auto noValue = [&]() { if (auto value = attributable->getAttributeValue("format"); value) {
if (value.has_value()) auto functions = evaluator->getCustomFunctions();
LogConsole::abortEvaluation(hex::format("provided a value to attribute '{}' which doesn't take one", name), node); if (!functions.contains(*value))
return true; LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node);
};
if (name == "color" && requiresValue()) { const auto &function = functions[*value];
u32 color = strtoul(value->c_str(), nullptr, 16); if (function.parameterCount != 1)
pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8); LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
} else if (name == "name" && requiresValue()) {
pattern->setDisplayName(*value);
} else if (name == "comment" && requiresValue()) {
pattern->setComment(*value);
} else if (name == "hidden" && noValue()) {
pattern->setHidden(true);
} else if (name == "no_unique_address" && noValue()) {
endOffset -= pattern->getSize();
} else if (name == "inline" && noValue()) {
auto inlinable = dynamic_cast<Inlinable *>(pattern);
if (inlinable == nullptr) pattern->setFormatterFunction(function);
LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node); }
else
inlinable->setInlined(true);
} else if (name == "format" && requiresValue()) { if (auto value = attributable->getAttributeValue("transform"); value) {
auto functions = evaluator->getCustomFunctions(); auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value)) if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node); LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
const auto &function = functions[*value]; const auto &function = functions[*value];
if (function.parameterCount != 1) if (function.parameterCount != 1)
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
pattern->setFormatterFunction(function); pattern->setTransformFunction(function);
} else if (name == "transform" && requiresValue()) { }
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
const auto &function = functions[*value]; if (auto value = attributable->getAttributeValue("pointer_base"); value) {
if (function.parameterCount != 1) auto functions = evaluator->getCustomFunctions();
LogConsole::abortEvaluation("transform function needs exactly one parameter", node); if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
pattern->setTransformFunction(function); const auto &function = functions[*value];
} else if (name == "pointer_base" && requiresValue()) { if (function.parameterCount != 1)
auto functions = evaluator->getCustomFunctions(); LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
const auto &function = functions[*value]; if (auto pointerPattern = dynamic_cast<PatternDataPointer *>(pattern)) {
if (function.parameterCount != 1) u128 pointerValue = pointerPattern->getPointedAtAddress();
LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
if (auto pointerPattern = dynamic_cast<PatternDataPointer *>(pattern)) { auto result = function.func(evaluator, { pointerValue });
u128 pointerValue = pointerPattern->getPointedAtAddress();
auto result = function.func(evaluator, { pointerValue }); if (!result.has_value())
LogConsole::abortEvaluation("pointer base function did not return a value", node);
if (!result.has_value()) pointerPattern->setPointedAtAddress(Token::literalToUnsigned(result.value()) + pointerValue);
LogConsole::abortEvaluation("pointer base function did not return a value", node); } else {
LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer");
pointerPattern->setPointedAtAddress(Token::literalToUnsigned(result.value()) + pointerValue);
} else {
LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer");
}
} }
} }
if (attributable->hasAttribute("hidden", false)) {
pattern->setHidden(true);
}
if (attributable->hasAttribute("no_unique_address", false)) {
endOffset -= pattern->getSize();
}
if (attributable->hasAttribute("inline", false)) {
auto inlinable = dynamic_cast<Inlinable *>(pattern);
if (inlinable == nullptr)
LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node);
else
inlinable->setInlined(true);
}
} }
class ASTNodeVariableDecl : public ASTNode, class ASTNodeVariableDecl : public ASTNode,
@ -905,11 +931,7 @@ namespace hex::pl {
if (dynamic_cast<ASTNodeBuiltinType *>(type)) if (dynamic_cast<ASTNodeBuiltinType *>(type))
pattern = createStaticArray(evaluator); pattern = createStaticArray(evaluator);
else if (auto attributable = dynamic_cast<Attributable *>(type)) { else if (auto attributable = dynamic_cast<Attributable *>(type)) {
auto &attributes = attributable->getAttributes(); bool isStaticType = attributable->hasAttribute("static", false);
bool isStaticType = std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) {
return attribute->getAttribute() == "static" && !attribute->getValue().has_value();
});
if (isStaticType) if (isStaticType)
pattern = createStaticArray(evaluator); pattern = createStaticArray(evaluator);
@ -1524,17 +1546,18 @@ namespace hex::pl {
delete field; delete field;
}; };
auto &attributes = this->getAttributes();
bool isLeftToRight = false; bool isLeftToRight = false;
if (this->hasAttribute("left_to_right", false))
if (std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) { return attribute->getAttribute() == "left_to_right" && !attribute->getValue().has_value(); }))
isLeftToRight = true; isLeftToRight = true;
else if (std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) { return attribute->getAttribute() == "right_to_left" && !attribute->getValue().has_value(); })) else if (this->hasAttribute("right_to_left", false))
isLeftToRight = false; isLeftToRight = false;
auto entries = this->m_entries;
if (isLeftToRight)
std::reverse(entries.begin(), entries.end());
evaluator->pushScope(pattern, fields); evaluator->pushScope(pattern, fields);
for (auto [name, bitSizeNode] : this->m_entries) { for (auto [name, bitSizeNode] : entries) {
auto literal = bitSizeNode->evaluate(evaluator); auto literal = bitSizeNode->evaluate(evaluator);
ON_SCOPE_EXIT { delete literal; }; ON_SCOPE_EXIT { delete literal; };
@ -1549,10 +1572,7 @@ namespace hex::pl {
auto field = new PatternDataBitfieldField(evaluator, evaluator->dataOffset(), bitOffset, bitSize, pattern); auto field = new PatternDataBitfieldField(evaluator, evaluator->dataOffset(), bitOffset, bitSize, pattern);
field->setVariableName(name); field->setVariableName(name);
if (isLeftToRight) fields.push_back(field);
fields.insert(fields.begin(), field);
else
fields.push_back(field);
} }
bitOffset += bitSize; bitOffset += bitSize;