#include #include #include #include #include #include #include namespace hex::lang { ASTNodeIntegerLiteral* Evaluator::evaluateScopeResolution(ASTNodeScopeResolution *node) { ASTNode *currScope = nullptr; for (const auto &identifier : node->getPath()) { if (currScope == nullptr) { if (!this->m_types.contains(identifier)) break; currScope = this->m_types[identifier.data()]; } else if (auto enumNode = dynamic_cast(currScope); enumNode != nullptr) { if (!enumNode->getEntries().contains(identifier)) break; else return evaluateMathematicalExpression(static_cast(enumNode->getEntries().at(identifier))); } } this->getConsole().abortEvaluation("failed to find identifier"); } PatternData* Evaluator::patternFromName(const std::vector &path) { std::vector currMembers; if (!this->m_currMembers.empty()) std::copy(this->m_currMembers.back()->begin(), this->m_currMembers.back()->end(), std::back_inserter(currMembers)); if (!this->m_globalMembers.empty()) std::copy(this->m_globalMembers.begin(), this->m_globalMembers.end(), std::back_inserter(currMembers)); PatternData *currPattern = nullptr; for (u32 i = 0; i < path.size(); i++) { const auto &identifier = path[i]; if (auto structPattern = dynamic_cast(currPattern); structPattern != nullptr) currMembers = structPattern->getMembers(); else if (auto unionPattern = dynamic_cast(currPattern); unionPattern != nullptr) currMembers = unionPattern->getMembers(); else if (auto pointerPattern = dynamic_cast(currPattern); pointerPattern != nullptr) { currPattern = pointerPattern->getPointedAtPattern(); i--; continue; } else if (currPattern != nullptr) this->getConsole().abortEvaluation("tried to access member of a non-struct/union type"); auto candidate = std::find_if(currMembers.begin(), currMembers.end(), [&](auto member) { return member->getVariableName() == identifier; }); if (candidate != currMembers.end()) currPattern = *candidate; else this->getConsole().abortEvaluation(hex::format("could not find identifier '%s'", identifier.c_str())); } if (auto pointerPattern = dynamic_cast(currPattern); pointerPattern != nullptr) currPattern = pointerPattern->getPointedAtPattern(); return currPattern; } ASTNodeIntegerLiteral* Evaluator::evaluateRValue(ASTNodeRValue *node) { if (this->m_currMembers.empty() && this->m_globalMembers.empty()) this->getConsole().abortEvaluation("no variables available"); if (node->getPath().size() == 1 && node->getPath()[0] == "$") return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, this->m_currOffset }); auto currPattern = this->patternFromName(node->getPath()); if (auto unsignedPattern = dynamic_cast(currPattern); unsignedPattern != nullptr) { u8 value[unsignedPattern->getSize()]; this->m_provider->read(unsignedPattern->getOffset(), value, unsignedPattern->getSize()); switch (unsignedPattern->getSize()) { case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, unsignedPattern->getEndian()) }); case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, unsignedPattern->getEndian()) }); case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, unsignedPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, unsignedPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, unsignedPattern->getEndian()) }); default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else if (auto signedPattern = dynamic_cast(currPattern); signedPattern != nullptr) { u8 value[unsignedPattern->getSize()]; this->m_provider->read(signedPattern->getOffset(), value, signedPattern->getSize()); switch (unsignedPattern->getSize()) { case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, signedPattern->getEndian()) }); case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, signedPattern->getEndian()) }); case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, signedPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, signedPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, signedPattern->getEndian()) }); default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else if (auto enumPattern = dynamic_cast(currPattern); enumPattern != nullptr) { u8 value[enumPattern->getSize()]; this->m_provider->read(enumPattern->getOffset(), value, enumPattern->getSize()); switch (enumPattern->getSize()) { case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, enumPattern->getEndian()) }); case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, enumPattern->getEndian()) }); case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, enumPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, enumPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, enumPattern->getEndian()) }); default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else this->getConsole().abortEvaluation("tried to use non-integer value in numeric expression"); } ASTNode* Evaluator::evaluateFunctionCall(ASTNodeFunctionCall *node) { std::vector evaluatedParams; ScopeExit paramCleanup([&] { for (auto ¶m : evaluatedParams) delete param; }); for (auto ¶m : node->getParams()) { if (auto numericExpression = dynamic_cast(param); numericExpression != nullptr) evaluatedParams.push_back(this->evaluateMathematicalExpression(numericExpression)); else if (auto stringLiteral = dynamic_cast(param); stringLiteral != nullptr) evaluatedParams.push_back(stringLiteral->clone()); } if (!ContentRegistry::PatternLanguageFunctions::getEntries().contains(node->getFunctionName().data())) this->getConsole().abortEvaluation(hex::format("no function named '%s' found", node->getFunctionName().data())); auto &function = ContentRegistry::PatternLanguageFunctions::getEntries()[node->getFunctionName().data()]; if (function.parameterCount == ContentRegistry::PatternLanguageFunctions::UnlimitedParameters) { ; // Don't check parameter count } else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::LessParametersThan) { if (evaluatedParams.size() >= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)) this->getConsole().abortEvaluation(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)); } else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::MoreParametersThan) { if (evaluatedParams.size() <= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)) this->getConsole().abortEvaluation(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)); } else if (function.parameterCount != evaluatedParams.size()) { this->getConsole().abortEvaluation(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount)); } return function.func(*this, evaluatedParams); } #define FLOAT_BIT_OPERATION(name) \ auto name(hex::floating_point auto left, auto right) { throw std::runtime_error(""); return 0; } \ auto name(auto left, hex::floating_point auto right) { throw std::runtime_error(""); return 0; } \ auto name(hex::floating_point auto left, hex::floating_point auto right) { throw std::runtime_error(""); return 0; } \ auto name(hex::integral auto left, hex::integral auto right) namespace { FLOAT_BIT_OPERATION(shiftLeft) { return left << right; } FLOAT_BIT_OPERATION(shiftRight) { return left >> right; } FLOAT_BIT_OPERATION(bitAnd) { return left & right; } FLOAT_BIT_OPERATION(bitOr) { return left | right; } FLOAT_BIT_OPERATION(bitXor) { return left ^ right; } FLOAT_BIT_OPERATION(bitNot) { return ~right; } FLOAT_BIT_OPERATION(modulus) { return left % right; } } ASTNodeIntegerLiteral* Evaluator::evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op) { auto newType = [&] { #define CHECK_TYPE(type) if (left->getType() == (type) || right->getType() == (type)) return (type) #define DEFAULT_TYPE(type) return (type) if (left->getType() == Token::ValueType::Any && right->getType() != Token::ValueType::Any) return right->getType(); if (left->getType() != Token::ValueType::Any && right->getType() == Token::ValueType::Any) return left->getType(); CHECK_TYPE(Token::ValueType::Double); CHECK_TYPE(Token::ValueType::Float); CHECK_TYPE(Token::ValueType::Unsigned128Bit); CHECK_TYPE(Token::ValueType::Signed128Bit); CHECK_TYPE(Token::ValueType::Unsigned64Bit); CHECK_TYPE(Token::ValueType::Signed64Bit); CHECK_TYPE(Token::ValueType::Unsigned32Bit); CHECK_TYPE(Token::ValueType::Signed32Bit); CHECK_TYPE(Token::ValueType::Unsigned16Bit); CHECK_TYPE(Token::ValueType::Signed16Bit); CHECK_TYPE(Token::ValueType::Unsigned8Bit); CHECK_TYPE(Token::ValueType::Signed8Bit); CHECK_TYPE(Token::ValueType::Character); CHECK_TYPE(Token::ValueType::Boolean); DEFAULT_TYPE(Token::ValueType::Signed32Bit); #undef CHECK_TYPE #undef DEFAULT_TYPE }(); try { return std::visit([&](auto &&leftValue, auto &&rightValue) -> ASTNodeIntegerLiteral * { switch (op) { case Token::Operator::Plus: return new ASTNodeIntegerLiteral({ newType, leftValue + rightValue }); case Token::Operator::Minus: return new ASTNodeIntegerLiteral({ newType, leftValue - rightValue }); case Token::Operator::Star: return new ASTNodeIntegerLiteral({ newType, leftValue * rightValue }); case Token::Operator::Slash: return new ASTNodeIntegerLiteral({ newType, leftValue / rightValue }); case Token::Operator::Percent: return new ASTNodeIntegerLiteral({ newType, modulus(leftValue, rightValue) }); case Token::Operator::ShiftLeft: return new ASTNodeIntegerLiteral({ newType, shiftLeft(leftValue, rightValue) }); case Token::Operator::ShiftRight: return new ASTNodeIntegerLiteral({ newType, shiftRight(leftValue, rightValue) }); case Token::Operator::BitAnd: return new ASTNodeIntegerLiteral({ newType, bitAnd(leftValue, rightValue) }); case Token::Operator::BitXor: return new ASTNodeIntegerLiteral({ newType, bitXor(leftValue, rightValue) }); case Token::Operator::BitOr: return new ASTNodeIntegerLiteral({ newType, bitOr(leftValue, rightValue) }); case Token::Operator::BitNot: return new ASTNodeIntegerLiteral({ newType, bitNot(leftValue, rightValue) }); case Token::Operator::BoolEquals: return new ASTNodeIntegerLiteral({ newType, leftValue == rightValue }); case Token::Operator::BoolNotEquals: return new ASTNodeIntegerLiteral({ newType, leftValue != rightValue }); case Token::Operator::BoolGreaterThan: return new ASTNodeIntegerLiteral({ newType, leftValue > rightValue }); case Token::Operator::BoolLessThan: return new ASTNodeIntegerLiteral({ newType, leftValue < rightValue }); case Token::Operator::BoolGreaterThanOrEquals: return new ASTNodeIntegerLiteral({ newType, leftValue >= rightValue }); case Token::Operator::BoolLessThanOrEquals: return new ASTNodeIntegerLiteral({ newType, leftValue <= rightValue }); case Token::Operator::BoolAnd: return new ASTNodeIntegerLiteral({ newType, leftValue && rightValue }); case Token::Operator::BoolXor: return new ASTNodeIntegerLiteral({ newType, leftValue && !rightValue || !leftValue && rightValue }); case Token::Operator::BoolOr: return new ASTNodeIntegerLiteral({ newType, leftValue || rightValue }); case Token::Operator::BoolNot: return new ASTNodeIntegerLiteral({ newType, !rightValue }); default: this->getConsole().abortEvaluation("invalid operator used in mathematical expression"); } }, left->getValue(), right->getValue()); } catch (std::runtime_error &e) { this->getConsole().abortEvaluation("bitwise operations on floating point numbers are forbidden"); } } ASTNodeIntegerLiteral* Evaluator::evaluateOperand(ASTNode *node) { if (auto exprLiteral = dynamic_cast(node); exprLiteral != nullptr) return exprLiteral; else if (auto exprExpression = dynamic_cast(node); exprExpression != nullptr) return evaluateMathematicalExpression(exprExpression); else if (auto exprRvalue = dynamic_cast(node); exprRvalue != nullptr) return evaluateRValue(exprRvalue); else if (auto exprScopeResolution = dynamic_cast(node); exprScopeResolution != nullptr) return evaluateScopeResolution(exprScopeResolution); else if (auto exprTernary = dynamic_cast(node); exprTernary != nullptr) return evaluateTernaryExpression(exprTernary); else if (auto exprFunctionCall = dynamic_cast(node); exprFunctionCall != nullptr) { auto returnValue = evaluateFunctionCall(exprFunctionCall); if (returnValue == nullptr) this->getConsole().abortEvaluation("function returning void used in expression"); else if (auto integerNode = dynamic_cast(returnValue); integerNode != nullptr) return integerNode; else this->getConsole().abortEvaluation("function not returning a numeric value used in expression"); } else this->getConsole().abortEvaluation("invalid operand"); } ASTNodeIntegerLiteral* Evaluator::evaluateTernaryExpression(ASTNodeTernaryExpression *node) { switch (node->getOperator()) { case Token::Operator::TernaryConditional: { auto condition = this->evaluateOperand(node->getFirstOperand()); SCOPE_EXIT( delete condition; ); if (std::visit([](auto &&value){ return value != 0; }, condition->getValue())) return this->evaluateOperand(node->getSecondOperand()); else return this->evaluateOperand(node->getThirdOperand()); } default: this->getConsole().abortEvaluation("invalid operator used in ternary expression"); } } ASTNodeIntegerLiteral* Evaluator::evaluateMathematicalExpression(ASTNodeNumericExpression *node) { auto leftInteger = this->evaluateOperand(node->getLeftOperand()); auto rightInteger = this->evaluateOperand(node->getRightOperand()); return evaluateOperator(leftInteger, rightInteger, node->getOperator()); } PatternData* Evaluator::evaluateAttributes(ASTNode *currNode, PatternData *currPattern) { auto attributableNode = dynamic_cast(currNode); if (attributableNode == nullptr) this->getConsole().abortEvaluation("attributes applied to invalid expression"); auto handleVariableAttributes = [this, &currPattern](auto attribute, auto value) { if (attribute == "color" && value.has_value()) currPattern->setColor(hex::changeEndianess(u32(strtoul(value->data(), nullptr, 0)) << 8, std::endian::big)); else if (attribute == "name" && value.has_value()) currPattern->setVariableName(value->data()); else if (attribute == "comment" && value.has_value()) currPattern->setComment(value->data()); else this->getConsole().abortEvaluation("unknown or invalid attribute"); }; auto &attributes = attributableNode->getAttributes(); if (attributes.empty()) return currPattern; if (auto variableDeclNode = dynamic_cast(currNode); variableDeclNode != nullptr) { for (auto &attribute : attributes) handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); } else if (auto arrayDeclNode = dynamic_cast(currNode); arrayDeclNode != nullptr) { for (auto &attribute : attributes) handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); } else if (auto pointerDeclNode = dynamic_cast(currNode); pointerDeclNode != nullptr) { for (auto &attribute : attributes) handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); } else if (auto structNode = dynamic_cast(currNode); structNode != nullptr) { this->getConsole().abortEvaluation("unknown or invalid attribute"); } else if (auto unionNode = dynamic_cast(currNode); unionNode != nullptr) { this->getConsole().abortEvaluation("unknown or invalid attribute"); } else if (auto enumNode = dynamic_cast(currNode); enumNode != nullptr) { this->getConsole().abortEvaluation("unknown or invalid attribute"); } else if (auto bitfieldNode = dynamic_cast(currNode); bitfieldNode != nullptr) { this->getConsole().abortEvaluation("unknown or invalid attribute"); } else this->getConsole().abortEvaluation("attributes applied to invalid expression"); return currPattern; } PatternData* Evaluator::evaluateBuiltinType(ASTNodeBuiltinType *node) { auto &type = node->getType(); auto typeSize = Token::getTypeSize(type); PatternData *pattern; if (type == Token::ValueType::Character) pattern = new PatternDataCharacter(this->m_currOffset); else if (type == Token::ValueType::Boolean) pattern = new PatternDataBoolean(this->m_currOffset); else if (Token::isUnsigned(type)) pattern = new PatternDataUnsigned(this->m_currOffset, typeSize); else if (Token::isSigned(type)) pattern = new PatternDataSigned(this->m_currOffset, typeSize); else if (Token::isFloatingPoint(type)) pattern = new PatternDataFloat(this->m_currOffset, typeSize); else this->getConsole().abortEvaluation("invalid builtin type"); this->m_currOffset += typeSize; pattern->setTypeName(Token::getTypeName(type)); pattern->setEndian(this->getCurrentEndian()); return pattern; } void Evaluator::evaluateMember(ASTNode *node, std::vector &currMembers, bool increaseOffset) { auto startOffset = this->m_currOffset; if (auto memberVariableNode = dynamic_cast(node); memberVariableNode != nullptr) currMembers.push_back(this->evaluateVariable(memberVariableNode)); else if (auto memberArrayNode = dynamic_cast(node); memberArrayNode != nullptr) currMembers.push_back(this->evaluateArray(memberArrayNode)); else if (auto memberPointerNode = dynamic_cast(node); memberPointerNode != nullptr) currMembers.push_back(this->evaluatePointer(memberPointerNode)); else if (auto conditionalNode = dynamic_cast(node); conditionalNode != nullptr) { auto condition = this->evaluateMathematicalExpression(static_cast(conditionalNode->getCondition())); if (std::visit([](auto &&value) { return value != 0; }, condition->getValue())) { for (auto &statement : conditionalNode->getTrueBody()) { this->evaluateMember(statement, currMembers, increaseOffset); } } else { for (auto &statement : conditionalNode->getFalseBody()) { this->evaluateMember(statement, currMembers, increaseOffset); } } delete condition; } else this->getConsole().abortEvaluation("invalid struct member"); if (!increaseOffset) this->m_currOffset = startOffset; } PatternData* Evaluator::evaluateStruct(ASTNodeStruct *node) { std::vector memberPatterns; this->m_currMembers.push_back(&memberPatterns); SCOPE_EXIT( this->m_currMembers.pop_back(); ); auto startOffset = this->m_currOffset; for (auto &member : node->getMembers()) { this->evaluateMember(member, memberPatterns, true); } return this->evaluateAttributes(node, new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns)); } PatternData* Evaluator::evaluateUnion(ASTNodeUnion *node) { std::vector memberPatterns; this->m_currMembers.push_back(&memberPatterns); SCOPE_EXIT( this->m_currMembers.pop_back(); ); auto startOffset = this->m_currOffset; for (auto &member : node->getMembers()) { this->evaluateMember(member, memberPatterns, false); } size_t size = 0; for (const auto &pattern : memberPatterns) size = std::max(size, pattern->getSize()); this->m_currOffset += size; return this->evaluateAttributes(node, new PatternDataUnion(startOffset, size, memberPatterns)); } PatternData* Evaluator::evaluateEnum(ASTNodeEnum *node) { std::vector> entryPatterns; auto startOffset = this->m_currOffset; for (auto &[name, value] : node->getEntries()) { auto expression = dynamic_cast(value); if (expression == nullptr) this->getConsole().abortEvaluation("invalid expression in enum value"); auto valueNode = evaluateMathematicalExpression(expression); SCOPE_EXIT( delete valueNode; ); entryPatterns.push_back({{ valueNode->getType(), valueNode->getValue() }, name }); } auto underlyingType = dynamic_cast(node->getUnderlyingType()); if (underlyingType == nullptr) this->getConsole().abortEvaluation("enum underlying type was not ASTNodeTypeDecl. This is a bug"); size_t size; if (auto builtinType = dynamic_cast(underlyingType->getType()); builtinType != nullptr) size = Token::getTypeSize(builtinType->getType()); else this->getConsole().abortEvaluation("invalid enum underlying type"); this->m_currOffset += size; return this->evaluateAttributes(node, new PatternDataEnum(startOffset, size, entryPatterns)); } PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) { std::vector> entryPatterns; auto startOffset = this->m_currOffset; size_t bits = 0; for (auto &[name, value] : node->getEntries()) { auto expression = dynamic_cast(value); if (expression == nullptr) this->getConsole().abortEvaluation("invalid expression in bitfield field size"); auto valueNode = evaluateMathematicalExpression(expression); SCOPE_EXIT( delete valueNode; ); auto fieldBits = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) this->getConsole().abortEvaluation("bitfield entry size must be an integer value"); return static_cast(value); }, valueNode->getValue()); if (fieldBits > 64 || fieldBits <= 0) this->getConsole().abortEvaluation("bitfield entry must occupy between 1 and 64 bits"); bits += fieldBits; entryPatterns.emplace_back(name, fieldBits); } size_t size = (bits + 7) / 8; this->m_currOffset += size; return this->evaluateAttributes(node, new PatternDataBitfield(startOffset, size, entryPatterns)); } PatternData* Evaluator::evaluateType(ASTNodeTypeDecl *node) { auto type = node->getType(); this->m_endianStack.push_back(node->getEndian().value_or(this->m_defaultDataEndian)); PatternData *pattern; if (auto builtinTypeNode = dynamic_cast(type); builtinTypeNode != nullptr) return this->evaluateBuiltinType(builtinTypeNode); else if (auto typeDeclNode = dynamic_cast(type); typeDeclNode != nullptr) pattern = this->evaluateType(typeDeclNode); else if (auto structNode = dynamic_cast(type); structNode != nullptr) pattern = this->evaluateStruct(structNode); else if (auto unionNode = dynamic_cast(type); unionNode != nullptr) pattern = this->evaluateUnion(unionNode); else if (auto enumNode = dynamic_cast(type); enumNode != nullptr) pattern = this->evaluateEnum(enumNode); else if (auto bitfieldNode = dynamic_cast(type); bitfieldNode != nullptr) pattern = this->evaluateBitfield(bitfieldNode); else this->getConsole().abortEvaluation("type could not be evaluated"); if (!node->getName().empty()) pattern->setTypeName(node->getName().data()); pattern->setEndian(this->getCurrentEndian()); this->m_endianStack.pop_back(); return pattern; } PatternData* Evaluator::evaluateVariable(ASTNodeVariableDecl *node) { if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); this->m_currOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) this->getConsole().abortEvaluation("placement offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); } if (this->m_currOffset >= this->m_provider->getActualSize()) this->getConsole().abortEvaluation("variable placed out of range"); PatternData *pattern; if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) pattern = this->evaluateType(typeDecl); else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) pattern = this->evaluateBuiltinType(builtinTypeDecl); else this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); pattern->setVariableName(node->getName().data()); return this->evaluateAttributes(node, pattern); } PatternData* Evaluator::evaluateArray(ASTNodeArrayVariableDecl *node) { if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); this->m_currOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) this->getConsole().abortEvaluation("placement offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); } auto startOffset = this->m_currOffset; ASTNodeIntegerLiteral *valueNode; u64 arraySize = 0; if (node->getSize() != nullptr) { if (auto sizeNumericExpression = dynamic_cast(node->getSize()); sizeNumericExpression != nullptr) valueNode = evaluateMathematicalExpression(sizeNumericExpression); else this->getConsole().abortEvaluation("array size not a numeric expression"); SCOPE_EXIT( delete valueNode; ); arraySize = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) this->getConsole().abortEvaluation("array size must be an integer value"); return static_cast(value); }, valueNode->getValue()); if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) { if (auto builtinType = dynamic_cast(typeDecl->getType()); builtinType != nullptr) { if (builtinType->getType() == Token::ValueType::Padding) { this->m_currOffset += arraySize; return new PatternDataPadding(startOffset, arraySize); } } } } else { u8 currByte = 0x00; u64 offset = startOffset; do { this->m_provider->read(offset, &currByte, sizeof(u8)); offset += sizeof(u8); arraySize += sizeof(u8); } while (currByte != 0x00 && offset < this->m_provider->getSize()); } std::vector entries; std::optional color; for (s128 i = 0; i < arraySize; i++) { PatternData *entry; if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) entry = this->evaluateType(typeDecl); else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) { entry = this->evaluateBuiltinType(builtinTypeDecl); } else this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); entry->setVariableName(hex::format("[%llu]", (u64)i)); entry->setEndian(this->getCurrentEndian()); if (!color.has_value()) color = entry->getColor(); entry->setColor(color.value_or(0)); entries.push_back(entry); if (this->m_currOffset > this->m_provider->getActualSize()) this->getConsole().abortEvaluation("array exceeds size of file"); } PatternData *pattern; if (entries.empty()) { pattern = new PatternDataPadding(startOffset, 0); } else if (dynamic_cast(entries[0])) pattern = new PatternDataString(startOffset, (this->m_currOffset - startOffset), color.value_or(0)); else { if (node->getSize() == nullptr) this->getConsole().abortEvaluation("no bounds provided for array"); pattern = new PatternDataArray(startOffset, (this->m_currOffset - startOffset), entries, color.value_or(0)); } pattern->setVariableName(node->getName().data()); return this->evaluateAttributes(node, pattern); } PatternData* Evaluator::evaluatePointer(ASTNodePointerVariableDecl *node) { s128 pointerOffset; if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); pointerOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) this->getConsole().abortEvaluation("pointer offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); this->m_currOffset = pointerOffset; } else { pointerOffset = this->m_currOffset; } PatternData *sizeType; auto underlyingType = dynamic_cast(node->getSizeType()); if (underlyingType == nullptr) this->getConsole().abortEvaluation("underlying type is not ASTNodeTypeDecl. This is a bug"); if (auto builtinTypeNode = dynamic_cast(underlyingType->getType()); builtinTypeNode != nullptr) { sizeType = evaluateBuiltinType(builtinTypeNode); } else this->getConsole().abortEvaluation("pointer size is not a builtin type"); size_t pointerSize = sizeType->getSize(); u128 pointedAtOffset = 0; this->m_provider->read(pointerOffset, &pointedAtOffset, pointerSize); this->m_currOffset = hex::changeEndianess(pointedAtOffset, pointerSize, underlyingType->getEndian().value_or(this->m_defaultDataEndian)); delete sizeType; if (this->m_currOffset > this->m_provider->getActualSize()) this->getConsole().abortEvaluation("pointer points past the end of the data"); PatternData *pointedAt; if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) pointedAt = this->evaluateType(typeDecl); else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) pointedAt = this->evaluateBuiltinType(builtinTypeDecl); else this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); this->m_currOffset = pointerOffset + pointerSize; auto pattern = new PatternDataPointer(pointerOffset, pointerSize, pointedAt); pattern->setVariableName(node->getName().data()); pattern->setEndian(this->getCurrentEndian()); return this->evaluateAttributes(node, pattern); } std::optional> Evaluator::evaluate(const std::vector &ast) { this->m_globalMembers.clear(); this->m_currMembers.clear(); this->m_types.clear(); this->m_endianStack.clear(); this->m_currOffset = 0; try { for (const auto& node : ast) { this->m_endianStack.push_back(this->m_defaultDataEndian); if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { this->m_globalMembers.push_back(this->evaluateVariable(variableDeclNode)); } else if (auto arrayDeclNode = dynamic_cast(node); arrayDeclNode != nullptr) { this->m_globalMembers.push_back(this->evaluateArray(arrayDeclNode)); } else if (auto pointerDeclNode = dynamic_cast(node); pointerDeclNode != nullptr) { this->m_globalMembers.push_back(this->evaluatePointer(pointerDeclNode)); } else if (auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { this->m_types[typeDeclNode->getName().data()] = typeDeclNode->getType(); } else if (auto functionCallNode = dynamic_cast(node); functionCallNode != nullptr) { auto result = this->evaluateFunctionCall(functionCallNode); delete result; } this->m_endianStack.clear(); } } catch (LogConsole::EvaluateError &e) { this->getConsole().log(LogConsole::Level::Error, e); return { }; } return this->m_globalMembers; } }