1
0
mirror of synced 2025-01-29 19:17:28 +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;
}
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:
std::vector<ASTNodeAttribute *> m_attributes;
};
@ -692,91 +718,91 @@ namespace hex::pl {
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();
evaluator->dataOffset() = pattern->getOffset();
ON_SCOPE_EXIT { evaluator->dataOffset() = endOffset; };
for (ASTNodeAttribute *attribute : attributable->getAttributes()) {
auto &name = attribute->getAttribute();
auto value = attribute->getValue();
if (auto value = attributable->getAttributeValue("color"); value) {
u32 color = strtoul(value->c_str(), nullptr, 16);
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 (!value.has_value())
LogConsole::abortEvaluation(hex::format("used attribute '{}' without providing a value", name), node);
return true;
};
if (auto value = attributable->getAttributeValue("comment"); value) {
pattern->setComment(*value);
}
auto noValue = [&]() {
if (value.has_value())
LogConsole::abortEvaluation(hex::format("provided a value to attribute '{}' which doesn't take one", name), node);
return true;
};
if (auto value = attributable->getAttributeValue("format"); value) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node);
if (name == "color" && requiresValue()) {
u32 color = strtoul(value->c_str(), nullptr, 16);
pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8);
} 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);
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
if (inlinable == nullptr)
LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node);
else
inlinable->setInlined(true);
pattern->setFormatterFunction(function);
}
} else if (name == "format" && requiresValue()) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node);
if (auto value = attributable->getAttributeValue("transform"); value) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
pattern->setFormatterFunction(function);
} else if (name == "transform" && requiresValue()) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
pattern->setTransformFunction(function);
}
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
if (auto value = attributable->getAttributeValue("pointer_base"); value) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
pattern->setTransformFunction(function);
} else if (name == "pointer_base" && requiresValue()) {
auto functions = evaluator->getCustomFunctions();
if (!functions.contains(*value))
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
const auto &function = functions[*value];
if (function.parameterCount != 1)
LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
if (auto pointerPattern = dynamic_cast<PatternDataPointer *>(pattern)) {
u128 pointerValue = pointerPattern->getPointedAtAddress();
if (auto pointerPattern = dynamic_cast<PatternDataPointer *>(pattern)) {
u128 pointerValue = pointerPattern->getPointedAtAddress();
auto result = function.func(evaluator, { pointerValue });
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())
LogConsole::abortEvaluation("pointer base function did not return a value", node);
pointerPattern->setPointedAtAddress(Token::literalToUnsigned(result.value()) + pointerValue);
} 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,
@ -905,11 +931,7 @@ namespace hex::pl {
if (dynamic_cast<ASTNodeBuiltinType *>(type))
pattern = createStaticArray(evaluator);
else if (auto attributable = dynamic_cast<Attributable *>(type)) {
auto &attributes = attributable->getAttributes();
bool isStaticType = std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) {
return attribute->getAttribute() == "static" && !attribute->getValue().has_value();
});
bool isStaticType = attributable->hasAttribute("static", false);
if (isStaticType)
pattern = createStaticArray(evaluator);
@ -1524,17 +1546,18 @@ namespace hex::pl {
delete field;
};
auto &attributes = this->getAttributes();
bool isLeftToRight = false;
if (std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) { return attribute->getAttribute() == "left_to_right" && !attribute->getValue().has_value(); }))
if (this->hasAttribute("left_to_right", false))
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;
auto entries = this->m_entries;
if (isLeftToRight)
std::reverse(entries.begin(), entries.end());
evaluator->pushScope(pattern, fields);
for (auto [name, bitSizeNode] : this->m_entries) {
for (auto [name, bitSizeNode] : entries) {
auto literal = bitSizeNode->evaluate(evaluator);
ON_SCOPE_EXIT { delete literal; };
@ -1549,10 +1572,7 @@ namespace hex::pl {
auto field = new PatternDataBitfieldField(evaluator, evaluator->dataOffset(), bitOffset, bitSize, pattern);
field->setVariableName(name);
if (isLeftToRight)
fields.insert(fields.begin(), field);
else
fields.push_back(field);
fields.push_back(field);
}
bitOffset += bitSize;