#include "lang/validator.hpp" #include #include #include "helpers/utils.hpp" namespace hex::lang { Validator::Validator() { } bool Validator::validate(const std::vector& ast) { std::unordered_set identifiers; try { for (const auto &node : ast) { if (node == nullptr) throwValidateError("nullptr in AST. This is a bug!", 1); if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { if (!identifiers.insert(variableDeclNode->getName().data()).second) throwValidateError(hex::format("redefinition of identifier '%s'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber()); this->validate({ variableDeclNode->getType() }); } else if (auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { if (!identifiers.insert(typeDeclNode->getName().data()).second) throwValidateError(hex::format("redefinition of identifier '%s'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber()); this->validate({ typeDeclNode->getType() }); } else if (auto structNode = dynamic_cast(node); structNode != nullptr) { this->validate(structNode->getMembers()); } else if (auto unionNode = dynamic_cast(node); unionNode != nullptr) { this->validate(unionNode->getMembers()); } else if (auto enumNode = dynamic_cast(node); enumNode != nullptr) { std::unordered_set enumIdentifiers; for (auto &[name, value] : enumNode->getEntries()) { if (!enumIdentifiers.insert(name).second) throwValidateError(hex::format("redefinition of enum constant '%s'", name.c_str()), value->getLineNumber()); } } } } catch (ValidatorError &e) { this->m_error = e; return false; } return true; } void Validator::printAST(const std::vector& ast){ #if DEBUG #define INDENT_VALUE indent, ' ' static s32 indent = -2; indent += 2; for (const auto &node : ast) { if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { if (auto offset = dynamic_cast(variableDeclNode->getPlacementOffset()); offset != nullptr) { printf("%*c ASTNodeVariableDecl (%s) @\n", INDENT_VALUE, variableDeclNode->getName().data()); printAST({ offset }); } else printf("%*c ASTNodeVariableDecl (%s)\n", INDENT_VALUE, variableDeclNode->getName().data()); printAST({ variableDeclNode->getType() }); } else if (auto pointerDeclNode = dynamic_cast(node); pointerDeclNode != nullptr) { if (auto offset = dynamic_cast(pointerDeclNode->getPlacementOffset()); offset != nullptr) { printf("%*c ASTNodePointerVariableDecl (*%s) @\n", INDENT_VALUE, pointerDeclNode->getName().data()); printAST({ offset }); } else printf("%*c ASTNodePointerVariableDecl (*%s)\n", INDENT_VALUE, pointerDeclNode->getName().data()); printAST({ pointerDeclNode->getType() }); printAST({ pointerDeclNode->getSizeType() }); } else if (auto arrayDeclNode = dynamic_cast(node); arrayDeclNode != nullptr) { auto sizeExpr = dynamic_cast(arrayDeclNode->getSize()); if (sizeExpr == nullptr) { printf("%*c Invalid size!\n", INDENT_VALUE); continue; } if (auto offset = dynamic_cast(arrayDeclNode->getPlacementOffset()); offset != nullptr) { printf("%*c ASTNodeArrayVariableDecl (%s[]) @\n", INDENT_VALUE, arrayDeclNode->getName().data()); printAST({ sizeExpr }); printAST({ offset }); } else { printf("%*c ASTNodeArrayVariableDecl (%s[])\n", INDENT_VALUE, arrayDeclNode->getName().data()); printAST({ sizeExpr }); } printAST({ arrayDeclNode->getType() }); printAST({ arrayDeclNode->getSize() }); } else if (auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { printf("%*c ASTNodeTypeDecl (%s %s)\n", INDENT_VALUE, typeDeclNode->getEndian().value_or(std::endian::native) == std::endian::little ? "le" : "be", typeDeclNode->getName().empty() ? "" : typeDeclNode->getName().data()); printAST({ typeDeclNode->getType() }); } else if (auto builtinTypeNode = dynamic_cast(node); builtinTypeNode != nullptr) { std::string typeName = Token::getTypeName(builtinTypeNode->getType()); printf("%*c ASTNodeTypeDecl (%s)\n", INDENT_VALUE, typeName.c_str()); } else if (auto integerLiteralNode = dynamic_cast(node); integerLiteralNode != nullptr) { printf("%*c ASTNodeIntegerLiteral %lld\n", INDENT_VALUE, (s64)std::get(integerLiteralNode->getValue())); } else if (auto numericExpressionNode = dynamic_cast(node); numericExpressionNode != nullptr) { std::string op; switch (numericExpressionNode->getOperator()) { case Token::Operator::Plus: op = "+"; break; case Token::Operator::Minus: op = "-"; break; case Token::Operator::Star: op = "*"; break; case Token::Operator::Slash: op = "/"; break; case Token::Operator::ShiftLeft: op = ">>"; break; case Token::Operator::ShiftRight: op = "<<"; break; case Token::Operator::BitAnd: op = "&"; break; case Token::Operator::BitOr: op = "|"; break; case Token::Operator::BitXor: op = "^"; break; default: op = "???"; } printf("%*c ASTNodeNumericExpression %s\n", INDENT_VALUE, op.c_str()); printf("%*c Left:\n", INDENT_VALUE); printAST({ numericExpressionNode->getLeftOperand() }); printf("%*c Right:\n", INDENT_VALUE); printAST({ numericExpressionNode->getRightOperand() }); } else if (auto structNode = dynamic_cast(node); structNode != nullptr) { printf("%*c ASTNodeStruct\n", INDENT_VALUE); printAST(structNode->getMembers()); } else if (auto unionNode = dynamic_cast(node); unionNode != nullptr) { printf("%*c ASTNodeUnion\n", INDENT_VALUE); printAST(unionNode->getMembers()); } else if (auto enumNode = dynamic_cast(node); enumNode != nullptr) { printf("%*c ASTNodeEnum\n", INDENT_VALUE); for (const auto &[name, entry] : enumNode->getEntries()) { printf("%*c ::%s\n", INDENT_VALUE, name.c_str()); printAST({ entry }); } } else if (auto bitfieldNode = dynamic_cast(node); bitfieldNode != nullptr) { printf("%*c ASTNodeBitfield\n", INDENT_VALUE); for (const auto &[name, entry] : bitfieldNode->getEntries()) { printf("%*c %s : \n", INDENT_VALUE, name.c_str()); printAST({ entry }); } } else if (auto rvalueNode = dynamic_cast(node); rvalueNode != nullptr) { printf("%*c ASTNodeRValue\n", INDENT_VALUE); printf("%*c ", INDENT_VALUE); for (const auto &path : rvalueNode->getPath()) printf("%s.", path.c_str()); printf("\n"); } else { printf("%*c Invalid AST node!\n", INDENT_VALUE); } } indent -= 2; #undef INDENT_VALUE #endif } }