diff --git a/include/lang/ast_node.hpp b/include/lang/ast_node.hpp index ff925adec..52622c9bb 100644 --- a/include/lang/ast_node.hpp +++ b/include/lang/ast_node.hpp @@ -20,19 +20,21 @@ namespace hex::lang { Scope, }; - explicit ASTNode(Type type) : m_type(type) {} + explicit ASTNode(Type type, u32 lineNumber) : m_type(type), m_lineNumber(lineNumber) {} virtual ~ASTNode() = default; Type getType() { return this->m_type; } + u32 getLineNumber() { return this->m_lineNumber; } private: Type m_type; + u32 m_lineNumber; }; class ASTNodeVariableDecl : public ASTNode { public: - explicit ASTNodeVariableDecl(const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional offset = { }, size_t arraySize = 1, std::optional arraySizeVariable = { }, std::optional pointerSize = { }) - : ASTNode(Type::VariableDecl), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize), m_arraySizeVariable(arraySizeVariable), m_pointerSize(pointerSize) { } + explicit ASTNodeVariableDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional offset = { }, size_t arraySize = 1, std::optional arraySizeVariable = { }, std::optional pointerSize = { }) + : ASTNode(Type::VariableDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize), m_arraySizeVariable(arraySizeVariable), m_pointerSize(pointerSize) { } const Token::TypeToken::Type& getVariableType() const { return this->m_type; } const std::string& getCustomVariableTypeName() const { return this->m_customTypeName; } @@ -53,7 +55,7 @@ namespace hex::lang { class ASTNodeScope : public ASTNode { public: - explicit ASTNodeScope(std::vector nodes) : ASTNode(Type::Scope), m_nodes(nodes) { } + explicit ASTNodeScope(u32 lineNumber, std::vector nodes) : ASTNode(Type::Scope, lineNumber), m_nodes(nodes) { } std::vector &getNodes() { return this->m_nodes; } private: @@ -62,8 +64,8 @@ namespace hex::lang { class ASTNodeStruct : public ASTNode { public: - explicit ASTNodeStruct(std::string name, std::vector nodes) - : ASTNode(Type::Struct), m_name(name), m_nodes(nodes) { } + explicit ASTNodeStruct(u32 lineNumber, std::string name, std::vector nodes) + : ASTNode(Type::Struct, lineNumber), m_name(name), m_nodes(nodes) { } const std::string& getName() const { return this->m_name; } std::vector &getNodes() { return this->m_nodes; } @@ -74,8 +76,8 @@ namespace hex::lang { class ASTNodeUnion : public ASTNode { public: - explicit ASTNodeUnion(std::string name, std::vector nodes) - : ASTNode(Type::Union), m_name(name), m_nodes(nodes) { } + explicit ASTNodeUnion(u32 lineNumber, std::string name, std::vector nodes) + : ASTNode(Type::Union, lineNumber), m_name(name), m_nodes(nodes) { } const std::string& getName() const { return this->m_name; } std::vector &getNodes() { return this->m_nodes; } @@ -86,8 +88,8 @@ namespace hex::lang { class ASTNodeBitField : public ASTNode { public: - explicit ASTNodeBitField(std::string name, std::vector> fields) - : ASTNode(Type::Bitfield), m_name(name), m_fields(fields) { } + explicit ASTNodeBitField(u32 lineNumber, std::string name, std::vector> fields) + : ASTNode(Type::Bitfield, lineNumber), m_name(name), m_fields(fields) { } const std::string& getName() const { return this->m_name; } std::vector> &getFields() { return this->m_fields; } @@ -98,8 +100,8 @@ namespace hex::lang { class ASTNodeTypeDecl : public ASTNode { public: - explicit ASTNodeTypeDecl(const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "") - : ASTNode(Type::TypeDecl), m_type(type), m_name(name), m_customTypeName(customTypeName) { } + explicit ASTNodeTypeDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "") + : ASTNode(Type::TypeDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName) { } const std::string& getTypeName() const { return this->m_name; }; @@ -112,8 +114,8 @@ namespace hex::lang { class ASTNodeEnum : public ASTNode { public: - explicit ASTNodeEnum(const Token::TypeToken::Type &type, const std::string &name) - : ASTNode(Type::Enum), m_type(type), m_name(name) { } + explicit ASTNodeEnum(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name) + : ASTNode(Type::Enum, lineNumber), m_type(type), m_name(name) { } const std::string& getName() const { return this->m_name; }; diff --git a/include/lang/evaluator.hpp b/include/lang/evaluator.hpp index 6abd3bc4d..9176818ff 100644 --- a/include/lang/evaluator.hpp +++ b/include/lang/evaluator.hpp @@ -19,11 +19,14 @@ namespace hex::lang { std::pair> evaluate(const std::vector& ast); + const std::pair& getError() { return this->m_error; } + private: std::unordered_map m_types; prv::Provider* &m_provider; std::endian m_dataEndianess; + std::pair m_error; std::pair createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); std::pair createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); diff --git a/include/lang/lexer.hpp b/include/lang/lexer.hpp index 2711420de..c78ec7a60 100644 --- a/include/lang/lexer.hpp +++ b/include/lang/lexer.hpp @@ -14,6 +14,11 @@ namespace hex::lang { Lexer(); std::pair> lex(const std::string& code); + + const std::pair& getError() { return this->m_error; } + + private: + std::pair m_error; }; } \ No newline at end of file diff --git a/include/lang/parser.hpp b/include/lang/parser.hpp index 9a10657b9..8c9d9511c 100644 --- a/include/lang/parser.hpp +++ b/include/lang/parser.hpp @@ -12,8 +12,37 @@ namespace hex::lang { public: Parser(); + using TokenIter = std::vector::const_iterator; + std::pair> parse(const std::vector &tokens); + const std::pair& getError() { return this->m_error; } + + private: + std::pair m_error; + + + ASTNode* parseBuiltinVariableDecl(TokenIter &curr); + ASTNode* parseCustomTypeVariableDecl(TokenIter &curr); + ASTNode* parseBuiltinPointerVariableDecl(TokenIter &curr); + ASTNode* parseCustomTypePointerVariableDecl(TokenIter &curr); + ASTNode* parseBuiltinArrayDecl(TokenIter &curr); + ASTNode* parseCustomTypeArrayDecl(TokenIter &curr); + ASTNode* parseBuiltinVariableArrayDecl(TokenIter &curr); + ASTNode* parseCustomTypeVariableArrayDecl(TokenIter &curr); + ASTNode* parsePaddingDecl(TokenIter &curr); + ASTNode* parseFreeBuiltinVariableDecl(TokenIter &curr); + ASTNode* parseFreeCustomTypeVariableDecl(TokenIter &curr); + ASTNode* parseStruct(TokenIter &curr); + ASTNode* parseUnion(TokenIter &curr); + ASTNode* parseEnum(TokenIter &curr); + ASTNode *parseBitField(TokenIter &curr); + ASTNode *parseScope(TokenIter &curr); + std::optional parseUsingDeclaration(TokenIter &curr); + std::optional> parseStatement(TokenIter &curr); + + std::vector parseTillToken(TokenIter &curr, Token::Type endTokenType); + bool tryConsume(TokenIter &curr, std::initializer_list tokenTypes); }; } \ No newline at end of file diff --git a/include/lang/preprocessor.hpp b/include/lang/preprocessor.hpp index 98fee1631..13381582a 100644 --- a/include/lang/preprocessor.hpp +++ b/include/lang/preprocessor.hpp @@ -19,13 +19,17 @@ namespace hex::lang { std::pair preprocess(const std::string& code, bool initialRun = true); void addPragmaHandler(std::string pragmaType, std::function function); - void addDefaultPragramHandlers(); + void addDefaultPragmaHandlers(); + + const std::pair& getError() { return this->m_error; } private: std::unordered_map> m_pragmaHandlers; std::set> m_defines; std::set> m_pragmas; + + std::pair m_error; }; } \ No newline at end of file diff --git a/include/lang/token.hpp b/include/lang/token.hpp index 0a25d86e1..ef9554196 100644 --- a/include/lang/token.hpp +++ b/include/lang/token.hpp @@ -63,5 +63,7 @@ namespace hex::lang { Padding = 0x1F } type; } typeToken; + + u32 lineNumber; }; } \ No newline at end of file diff --git a/include/lang/validator.hpp b/include/lang/validator.hpp index cf12c46a8..a0548b7ce 100644 --- a/include/lang/validator.hpp +++ b/include/lang/validator.hpp @@ -15,6 +15,11 @@ namespace hex::lang { Validator(); bool validate(const std::vector& ast); + + const std::pair& getError() { return this->m_error; } + + private: + std::pair m_error; }; } \ No newline at end of file diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index 884bbb8f8..f5241c621 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -14,8 +14,10 @@ namespace hex::lang { auto structNode = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (structNode == nullptr) + if (structNode == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } size_t structSize = 0; for (const auto &node : structNode->getNodes()) { @@ -62,10 +64,12 @@ namespace hex::lang { } } - if (!arraySize.has_value()) + if (!arraySize.has_value()) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a previous member of '%s'", member->getArraySizeVariable().value().c_str(), varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } - ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); + ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getLineNumber(), member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset); } @@ -97,8 +101,10 @@ namespace hex::lang { auto unionNode = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (unionNode == nullptr) + if (unionNode == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } size_t unionSize = 0; for (const auto &node : unionNode->getNodes()) { @@ -148,10 +154,12 @@ namespace hex::lang { } } - if (!arraySize.has_value()) + if (!arraySize.has_value()) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a previous member of '%s'", member->getArraySizeVariable().value().c_str(), varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } - ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); + ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getLineNumber(), member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset); } @@ -179,12 +187,12 @@ namespace hex::lang { } std::pair Evaluator::createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - std::vector> enumValues; - auto *enumType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (enumType == nullptr) + if (enumType == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } size_t size = getTypeSize(enumType->getUnderlyingType()); @@ -195,8 +203,10 @@ namespace hex::lang { auto *bitfieldType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (bitfieldType == nullptr) + if (bitfieldType == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } size_t size = 0; for (auto &[fieldName, fieldSize] : bitfieldType->getFields()) @@ -215,7 +225,7 @@ namespace hex::lang { size_t arrayOffset = 0; std::optional arrayColor; for (u32 i = 0; i < varDeclNode->getArraySize(); i++) { - ASTNodeVariableDecl *nonArrayVarDeclNode = new ASTNodeVariableDecl(varDeclNode->getVariableType(), "[" + std::to_string(i) + "]", varDeclNode->getCustomVariableTypeName(), varDeclNode->getOffset(), 1); + ASTNodeVariableDecl *nonArrayVarDeclNode = new ASTNodeVariableDecl(varDeclNode->getLineNumber(), varDeclNode->getVariableType(), "[" + std::to_string(i) + "]", varDeclNode->getCustomVariableTypeName(), varDeclNode->getOffset(), 1); if (varDeclNode->getVariableType() == Token::TypeToken::Type::Padding) { @@ -263,8 +273,10 @@ namespace hex::lang { std::pair Evaluator::createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { auto &currType = this->m_types[varDeclNode->getCustomVariableTypeName()]; - if (currType == nullptr) + if (currType == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } switch (currType->getType()) { case ASTNode::Type::Struct: @@ -286,8 +298,10 @@ namespace hex::lang { auto type = varDeclNode->getVariableType(); if (type == Token::TypeToken::Type::CustomType) { const auto &currType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (currType == nullptr) + if (currType == nullptr) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; return { nullptr, 0 }; + } type = currType->getAssignedType(); } diff --git a/source/lang/lexer.cpp b/source/lang/lexer.cpp index 61aaf5f3e..60af18b8e 100644 --- a/source/lang/lexer.cpp +++ b/source/lang/lexer.cpp @@ -69,6 +69,8 @@ namespace hex::lang { std::vector tokens; u32 offset = 0; + u32 lineNumber = 1; + while (offset < code.length()) { // Handle comments @@ -85,6 +87,8 @@ namespace hex::lang { } else if (offset < code.length() && code[offset] == '*') { offset++; while (offset < (code.length() - 1)) { + if (code[offset] == '\n') lineNumber++; + if (code[offset] == '*' && code[offset + 1] == '/') break; offset++; @@ -100,66 +104,77 @@ namespace hex::lang { break; if (std::isblank(c) || std::isspace(c)) { + if (code[offset] == '\n') lineNumber++; offset += 1; } else if (c == ';') { - tokens.push_back({ .type = Token::Type::EndOfExpression }); + tokens.push_back({ .type = Token::Type::EndOfExpression, .lineNumber = lineNumber }); offset += 1; } else if (c == '{') { - tokens.push_back({ .type = Token::Type::ScopeOpen }); + tokens.push_back({ .type = Token::Type::ScopeOpen, .lineNumber = lineNumber }); offset += 1; } else if (c == '}') { - tokens.push_back({ .type = Token::Type::ScopeClose }); + tokens.push_back({ .type = Token::Type::ScopeClose, .lineNumber = lineNumber }); offset += 1; } else if (c == '[') { - tokens.push_back({ .type = Token::Type::ArrayOpen }); + tokens.push_back({ .type = Token::Type::ArrayOpen, .lineNumber = lineNumber }); offset += 1; } else if (c == ']') { - tokens.push_back({.type = Token::Type::ArrayClose}); + tokens.push_back({.type = Token::Type::ArrayClose, .lineNumber = lineNumber }); offset += 1; } else if (c == ',') { - tokens.push_back({ .type = Token::Type::Separator }); + tokens.push_back({ .type = Token::Type::Separator, .lineNumber = lineNumber }); offset += 1; } else if (c == '@') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::AtDeclaration } }); + tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::AtDeclaration }, .lineNumber = lineNumber }); offset += 1; } else if (c == '=') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Assignment } }); + tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Assignment }, .lineNumber = lineNumber }); offset += 1; } else if (c == ':') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit } }); + tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit }, .lineNumber = lineNumber }); offset += 1; } else if (c == '*') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Star } }); + tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Star }, .lineNumber = lineNumber }); offset += 1; } else if (c == '\'') { offset += 1; - if (offset >= code.length()) + if (offset >= code.length()) { + this->m_error = { lineNumber, "Invalid character literal" }; return { ResultLexicalError, { } }; + } char character = code[offset]; if (character == '\\') { offset += 1; - if (offset >= code.length()) + if (offset >= code.length()) { + this->m_error = { lineNumber, "Invalid character literal" }; return { ResultLexicalError, { } }; + } - if (code[offset] != '\\' && code[offset] != '\'') + if (code[offset] != '\\' && code[offset] != '\'') { + this->m_error = { lineNumber, "Invalid escape sequence" }; return { ResultLexicalError, { } }; + } character = code[offset]; } else { - if (code[offset] == '\\' || code[offset] == '\'') + if (code[offset] == '\\' || code[offset] == '\'' || character == '\n' || character == '\r') { + this->m_error = { lineNumber, "Invalid character literal" }; return { ResultLexicalError, { } }; + } } offset += 1; - if (offset >= code.length() || code[offset] != '\'') + if (offset >= code.length() || code[offset] != '\'') { + this->m_error = { lineNumber, "Missing terminating ' after character literal" }; return { ResultLexicalError, { } }; + } - tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = character } }); + tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = character }, .lineNumber = lineNumber }); offset += 1; } else if (std::isalpha(c)) { @@ -168,48 +183,48 @@ namespace hex::lang { // Check for reserved keywords if (identifier == "struct") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct } }); + tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct }, .lineNumber = lineNumber }); else if (identifier == "union") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Union } }); + tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Union }, .lineNumber = lineNumber }); else if (identifier == "using") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using } }); + tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using }, .lineNumber = lineNumber }); else if (identifier == "enum") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Enum } }); + tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Enum }, .lineNumber = lineNumber }); else if (identifier == "bitfield") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Bitfield } }); + tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Bitfield }, .lineNumber = lineNumber }); // Check for built-in types else if (identifier == "u8") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned8Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned8Bit }, .lineNumber = lineNumber }); else if (identifier == "s8") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed8Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed8Bit }, .lineNumber = lineNumber }); else if (identifier == "u16") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned16Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned16Bit }, .lineNumber = lineNumber }); else if (identifier == "s16") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed16Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed16Bit }, .lineNumber = lineNumber }); else if (identifier == "u32") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned32Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned32Bit }, .lineNumber = lineNumber }); else if (identifier == "s32") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed32Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed32Bit }, .lineNumber = lineNumber }); else if (identifier == "u64") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned64Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned64Bit }, .lineNumber = lineNumber }); else if (identifier == "s64") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed64Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed64Bit }, .lineNumber = lineNumber }); else if (identifier == "u128") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned128Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned128Bit }, .lineNumber = lineNumber }); else if (identifier == "s128") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed128Bit } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed128Bit }, .lineNumber = lineNumber }); else if (identifier == "float") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Float } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Float }, .lineNumber = lineNumber }); else if (identifier == "double") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Double } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Double }, .lineNumber = lineNumber }); else if (identifier == "padding") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Padding } }); + tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Padding }, .lineNumber = lineNumber }); // If it's not a keyword and a builtin type, it has to be an identifier else - tokens.push_back({.type = Token::Type::Identifier, .identifierToken = { .identifier = identifier } }); + tokens.push_back({.type = Token::Type::Identifier, .identifierToken = { .identifier = identifier }, .lineNumber = lineNumber }); offset += identifier.length(); } else if (std::isdigit(c)) { @@ -218,15 +233,20 @@ namespace hex::lang { auto integer = parseInt(std::string_view(&code[offset], end)); - if (!integer.has_value()) + if (!integer.has_value()) { + this->m_error = { lineNumber, "Invalid integer literal" }; return { ResultLexicalError, {}}; + } - tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = integer.value() } }); + tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = integer.value() }, .lineNumber = lineNumber }); offset += (end - &code[offset]); - } else return { ResultLexicalError, {}}; + } else { + this->m_error = { lineNumber, "Unknown token" }; + return { ResultLexicalError, {} }; + } } - tokens.push_back({ .type = Token::Type::EndOfProgram }); + tokens.push_back({ .type = Token::Type::EndOfProgram, .lineNumber = lineNumber }); return { ResultSuccess, tokens }; } diff --git a/source/lang/parser.cpp b/source/lang/parser.cpp index 02b8d6f1e..16e891975 100644 --- a/source/lang/parser.cpp +++ b/source/lang/parser.cpp @@ -10,11 +10,7 @@ namespace hex::lang { } - using TokenIter = std::vector::const_iterator; - - std::vector parseTillToken(TokenIter &curr, Token::Type endTokenType); - - bool tryConsume(TokenIter &curr, std::initializer_list tokenTypes) { + bool Parser::tryConsume(TokenIter &curr, std::initializer_list tokenTypes) { std::vector::const_iterator originalPosition = curr; for (const auto& type : tokenTypes) { @@ -29,64 +25,90 @@ namespace hex::lang { } - ASTNode* parseBuiltinVariableDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-3].typeToken.type, curr[-2].identifierToken.identifier); + ASTNode* Parser::parseBuiltinVariableDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-3].lineNumber, curr[-3].typeToken.type, curr[-2].identifierToken.identifier); } - ASTNode* parseCustomTypeVariableDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-2].identifierToken.identifier, curr[-3].identifierToken.identifier); + ASTNode* Parser::parseCustomTypeVariableDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-3].lineNumber, Token::TypeToken::Type::CustomType, curr[-2].identifierToken.identifier, curr[-3].identifierToken.identifier); } - ASTNode* parseBuiltinPointerVariableDecl(TokenIter &curr) { + ASTNode* Parser::parseBuiltinPointerVariableDecl(TokenIter &curr) { auto pointerType = curr[-2].typeToken.type; - if (!isUnsigned(pointerType) || curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star || curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) + if (!isUnsigned(pointerType)) { + this->m_error = { curr->lineNumber, "Pointer size needs to be a unsigned type" }; return nullptr; + } - return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-4].identifierToken.identifier, "", { }, 1, { }, getTypeSize(pointerType)); + if (curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star) { + this->m_error = { curr->lineNumber, "Expected '*' for pointer definition" }; + return nullptr; + } + + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { + this->m_error = { curr->lineNumber, "Expected ':' after member name" }; + return nullptr; + } + + return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-4].identifierToken.identifier, "", { }, 1, { }, getTypeSize(pointerType)); } - ASTNode* parseCustomTypePointerVariableDecl(TokenIter &curr) { + ASTNode* Parser::parseCustomTypePointerVariableDecl(TokenIter &curr) { auto pointerType = curr[-2].typeToken.type; - if (!isUnsigned(pointerType) || curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star || curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) + if (!isUnsigned(pointerType)) { + this->m_error = { curr->lineNumber, "Pointer size needs to be a unsigned type" }; return nullptr; + } - return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 1, { }, getTypeSize(pointerType)); + if (curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star) { + this->m_error = { curr->lineNumber, "Expected '*' for pointer definition" }; + return nullptr; + } + + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { + this->m_error = { curr->lineNumber, "Expected ':' after member name" }; + return nullptr; + } + + return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 1, { }, getTypeSize(pointerType)); } - ASTNode* parseBuiltinArrayDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, curr[-3].integerToken.integer); + ASTNode* Parser::parseBuiltinArrayDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, curr[-3].integerToken.integer); } - ASTNode* parseCustomTypeArrayDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, curr[-3].integerToken.integer); + ASTNode* Parser::parseCustomTypeArrayDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, curr[-3].integerToken.integer); } - ASTNode* parseBuiltinVariableArrayDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, 0, curr[-3].identifierToken.identifier); + ASTNode* Parser::parseBuiltinVariableArrayDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, 0, curr[-3].identifierToken.identifier); } - ASTNode* parseCustomTypeVariableArrayDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 0, curr[-3].identifierToken.identifier); + ASTNode* Parser::parseCustomTypeVariableArrayDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 0, curr[-3].identifierToken.identifier); } - ASTNode* parsePaddingDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-5].typeToken.type, "", "", { }, curr[-3].integerToken.integer); + ASTNode* Parser::parsePaddingDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-5].lineNumber, curr[-5].typeToken.type, "", "", { }, curr[-3].integerToken.integer); } - ASTNode* parseFreeBuiltinVariableDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-5].typeToken.type, curr[-4].identifierToken.identifier, "", curr[-2].integerToken.integer); + ASTNode* Parser::parseFreeBuiltinVariableDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-5].lineNumber, curr[-5].typeToken.type, curr[-4].identifierToken.identifier, "", curr[-2].integerToken.integer); } - ASTNode* parseFreeCustomTypeVariableDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-5].identifierToken.identifier, curr[-2].integerToken.integer); + ASTNode* Parser::parseFreeCustomTypeVariableDecl(TokenIter &curr) { + return new ASTNodeVariableDecl(curr[-5].lineNumber, Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-5].identifierToken.identifier, curr[-2].integerToken.integer); } - ASTNode* parseStruct(TokenIter &curr) { + ASTNode* Parser::parseStruct(TokenIter &curr) { const std::string &structName = curr[-2].identifierToken.identifier; std::vector nodes; + u32 startLineNumber = curr[-3].lineNumber; + while (!tryConsume(curr, {Token::Type::ScopeClose})) { if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) nodes.push_back(parseBuiltinVariableDecl(curr)); @@ -103,6 +125,8 @@ namespace hex::lang { else if (tryConsume(curr, {Token::Type::Type, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) { if (curr[-5].typeToken.type != Token::TypeToken::Type::Padding) { for(auto &node : nodes) delete node; + + this->m_error = { curr[-5].lineNumber, "No member name provided" }; return nullptr; } nodes.push_back(parsePaddingDecl(curr)); @@ -110,21 +134,28 @@ namespace hex::lang { nodes.push_back(parseBuiltinPointerVariableDecl(curr)); else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) nodes.push_back(parseCustomTypePointerVariableDecl(curr)); - else break; + else { + for(auto &node : nodes) delete node; + this->m_error = { curr->lineNumber, "Invalid sequence, expected member declaration" }; + return nullptr; + } } if (!tryConsume(curr, {Token::Type::EndOfExpression})) { + this->m_error = { curr->lineNumber, "Expected ';' after struct definition" }; for(auto &node : nodes) delete node; return nullptr; } - return new ASTNodeStruct(structName, nodes); + return new ASTNodeStruct(startLineNumber, structName, nodes); } - ASTNode* parseUnion(TokenIter &curr) { + ASTNode* Parser::parseUnion(TokenIter &curr) { const std::string &unionName = curr[-2].identifierToken.identifier; std::vector nodes; + u32 startLineNumber = curr[-3].lineNumber; + while (!tryConsume(curr, {Token::Type::ScopeClose})) { if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) nodes.push_back(parseBuiltinVariableDecl(curr)); @@ -138,28 +169,39 @@ namespace hex::lang { nodes.push_back(parseBuiltinPointerVariableDecl(curr)); else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) nodes.push_back(parseCustomTypePointerVariableDecl(curr)); - else break; + else { + for(auto &node : nodes) delete node; + this->m_error = { curr->lineNumber, "Invalid sequence, expected member declaration" }; + return nullptr; + } } if (!tryConsume(curr, {Token::Type::EndOfExpression})) { for(auto &node : nodes) delete node; + this->m_error = { curr[-1].lineNumber, "Expected ';' after union definition" }; return nullptr; } - return new ASTNodeUnion(unionName, nodes); + return new ASTNodeUnion(startLineNumber, unionName, nodes); } - ASTNode* parseEnum(TokenIter &curr) { + ASTNode* Parser::parseEnum(TokenIter &curr) { const std::string &enumName = curr[-4].identifierToken.identifier; const Token::TypeToken::Type underlyingType = curr[-2].typeToken.type; - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) - return nullptr; + u32 startLineNumber = curr[-5].lineNumber; - if ((static_cast(underlyingType) & 0x0F) != 0x00) + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { + this->m_error = { curr[-3].lineNumber, "Expected ':' after enum name" }; return nullptr; + } - auto enumNode = new ASTNodeEnum(underlyingType, enumName); + if (!isUnsigned(underlyingType)) { + this->m_error = { curr[-3].lineNumber, "Underlying type needs to be an unsigned type" }; + return nullptr; + } + + auto enumNode = new ASTNodeEnum(startLineNumber, underlyingType, enumName); while (!tryConsume(curr, {Token::Type::ScopeClose})) { if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Separator }) || tryConsume(curr, { Token::Type::Identifier, Token::Type::ScopeClose })) { @@ -183,67 +225,83 @@ namespace hex::lang { } else { delete enumNode; + this->m_error = { curr->lineNumber, "Expected constant identifier" }; return nullptr; } } if (!tryConsume(curr, {Token::Type::EndOfExpression})) { delete enumNode; + this->m_error = { curr[-1].lineNumber, "Expected ';' after enum definition" }; return nullptr; } return enumNode; } - ASTNode *parseBitField(TokenIter &curr) { + ASTNode* Parser::parseBitField(TokenIter &curr) { const std::string &bitfieldName = curr[-2].identifierToken.identifier; std::vector> fields; + u32 startLineNumber = curr[-3].lineNumber; + while (!tryConsume(curr, {Token::Type::ScopeClose})) { if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { + this->m_error = { curr[-3].lineNumber, "Expected ':' after member name" }; return nullptr; + } fields.emplace_back(curr[-4].identifierToken.identifier, curr[-2].integerToken.integer); } - else break; + else { + this->m_error = { curr->lineNumber, "Invalid sequence, expected member declaration" }; + return nullptr; + } } - if (!tryConsume(curr, {Token::Type::EndOfExpression})) + if (!tryConsume(curr, {Token::Type::EndOfExpression})) { + this->m_error = { curr[-1].lineNumber, "Expected ';' after bitfield definition" }; return nullptr; + } - return new ASTNodeBitField(bitfieldName, fields); + return new ASTNodeBitField(startLineNumber, bitfieldName, fields); } - ASTNode *parseScope(TokenIter &curr) { - return new ASTNodeScope(parseTillToken(curr, Token::Type::ScopeClose)); + ASTNode* Parser::parseScope(TokenIter &curr) { + return new ASTNodeScope(curr[-1].lineNumber, parseTillToken(curr, Token::Type::ScopeClose)); } - std::optional parseUsingDeclaration(TokenIter &curr) { + std::optional Parser::parseUsingDeclaration(TokenIter &curr) { auto keyword = curr[-5].keywordToken; auto name = curr[-4].identifierToken; auto op = curr[-3].operatorToken; - if (keyword.keyword != Token::KeywordToken::Keyword::Using) + if (keyword.keyword != Token::KeywordToken::Keyword::Using) { + this->m_error = { curr[-5].lineNumber, "Invalid keyword. Expected 'using'" }; return { }; + } - if (op.op != Token::OperatorToken::Operator::Assignment) + if (op.op != Token::OperatorToken::Operator::Assignment) { + this->m_error = { curr[-3].lineNumber, "Invalid operator. Expected '='" }; return { }; + } if (curr[-2].type == Token::Type::Type) { auto type = curr[-2].typeToken; - return new ASTNodeTypeDecl(type.type, name.identifier); + return new ASTNodeTypeDecl(curr[-2].lineNumber, type.type, name.identifier); } else if (curr[-2].type == Token::Type::Identifier) { auto customType = curr[-2].identifierToken; - return new ASTNodeTypeDecl(Token::TypeToken::Type::CustomType, name.identifier, customType.identifier); + return new ASTNodeTypeDecl(curr[-2].lineNumber, Token::TypeToken::Type::CustomType, name.identifier, customType.identifier); } + this->m_error = { curr[-2].lineNumber, hex::format("'%s' does not name a type") }; return { }; } - std::optional> parseStatement(TokenIter &curr) { + std::optional> Parser::parseStatement(TokenIter &curr) { std::vector program; // Struct @@ -324,16 +382,28 @@ namespace hex::lang { program.push_back(usingDecl.value()); return program; - // Variable declaration with built-in type + // Variable placement declaration with built-in type } else if (tryConsume(curr, { Token::Type::Type, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { + this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; + for(auto &node : program) delete node; + return { }; + } + auto variableDecl = parseFreeBuiltinVariableDecl(curr); program.push_back(variableDecl); return program; - // Variable declaration with custom type + // Variable placement declaration with custom type } else if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { + if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { + this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; + for(auto &node : program) delete node; + return { }; + } + auto variableDecl = parseFreeCustomTypeVariableDecl(curr); program.push_back(variableDecl); @@ -342,11 +412,12 @@ namespace hex::lang { } else { for(auto &node : program) delete node; + this->m_error = { curr->lineNumber, "Invalid sequence" }; return { }; } } - std::vector parseTillToken(TokenIter &curr, Token::Type endTokenType) { + std::vector Parser::parseTillToken(TokenIter &curr, Token::Type endTokenType) { std::vector program; while (curr->type != endTokenType) { diff --git a/source/lang/preprocessor.cpp b/source/lang/preprocessor.cpp index 80a0ee83e..f5309fc4f 100644 --- a/source/lang/preprocessor.cpp +++ b/source/lang/preprocessor.cpp @@ -8,6 +8,7 @@ namespace hex::lang { std::pair Preprocessor::preprocess(const std::string& code, bool initialRun) { u32 offset = 0; + u32 lineNumber = 1; if (initialRun) { this->m_defines.clear(); @@ -136,6 +137,9 @@ namespace hex::lang { return { ResultPreprocessingError, "" }; } + if (code[offset] == '\n') + lineNumber++; + output += code[offset]; offset += 1; } @@ -168,7 +172,7 @@ namespace hex::lang { this->m_pragmaHandlers.emplace(pragmaType, function); } - void Preprocessor::addDefaultPragramHandlers() { + void Preprocessor::addDefaultPragmaHandlers() { this->addPragmaHandler("MIME", [](std::string value) { return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); }); diff --git a/source/lang/validator.cpp b/source/lang/validator.cpp index 498bcbb80..06e5208eb 100644 --- a/source/lang/validator.cpp +++ b/source/lang/validator.cpp @@ -3,6 +3,8 @@ #include #include +#include "utils.hpp" + namespace hex::lang { Validator::Validator() { @@ -19,73 +21,96 @@ namespace hex::lang { { // Check for duplicate variable names auto varDeclNode = static_cast(node); - if (!typeNames.insert(varDeclNode->getVariableName()).second) + if (!typeNames.insert(varDeclNode->getVariableName()).second) { + this->m_error = { varDeclNode->getLineNumber(), hex::format("Redefinition of variable '%s'", varDeclNode->getVariableName().c_str()) }; return false; + } if (varDeclNode->getArraySize() == 0 && !varDeclNode->getArraySizeVariable().has_value() || - varDeclNode->getArraySize() != 0 && varDeclNode->getArraySizeVariable().has_value()) + varDeclNode->getArraySize() != 0 && varDeclNode->getArraySizeVariable().has_value()) { + + this->m_error = { varDeclNode->getLineNumber(), "Invalid array size" }; return false; + } } break; case ASTNode::Type::TypeDecl: { // Check for duplicate type names auto typeDeclNode = static_cast(node); - if (!typeNames.insert(typeDeclNode->getTypeName()).second) + if (!typeNames.insert(typeDeclNode->getTypeName()).second) { + this->m_error = { typeDeclNode->getLineNumber(), hex::format("Redefinition of type '%s'", typeDeclNode->getTypeName().c_str()) }; return false; + } - if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType && !typeNames.contains(typeDeclNode->getAssignedCustomTypeName())) + if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType && !typeNames.contains(typeDeclNode->getAssignedCustomTypeName())) { + this->m_error = { typeDeclNode->getLineNumber(), "Type declaration without a name" }; return false; + } } break; case ASTNode::Type::Struct: { // Check for duplicate type name auto structNode = static_cast(node); - if (!typeNames.insert(structNode->getName()).second) + if (!typeNames.insert(structNode->getName()).second) { + this->m_error = { structNode->getLineNumber(), hex::format("Redeclaration of type '%s'", structNode->getName().c_str()) }; return false; + } // Check for duplicate member names std::unordered_set memberNames; for (const auto &member : structNode->getNodes()) - if (!memberNames.insert(static_cast(member)->getVariableName()).second) + if (!memberNames.insert(static_cast(member)->getVariableName()).second) { + this->m_error = { member->getLineNumber(), hex::format("Redeclaration of member '%s'", static_cast(member)->getVariableName().c_str()) }; return false; + } } break; case ASTNode::Type::Enum: { // Check for duplicate type name auto enumNode = static_cast(node); - if (!typeNames.insert(enumNode->getName()).second) + if (!typeNames.insert(enumNode->getName()).second) { + this->m_error = { enumNode->getLineNumber(), hex::format("Redeclaration of type '%s'", enumNode->getName().c_str()) }; return false; + } // Check for duplicate constant names std::unordered_set constantNames; for (const auto &[value, name] : enumNode->getValues()) - if (!constantNames.insert(name).second) + if (!constantNames.insert(name).second) { + this->m_error = { enumNode->getLineNumber(), hex::format("Redeclaration of enum constant '%s'", name.c_str()) }; return false; + } } break; case ASTNode::Type::Bitfield: { // Check for duplicate type name auto bitfieldNode = static_cast(node); - if (!typeNames.insert(bitfieldNode->getName()).second) + if (!typeNames.insert(bitfieldNode->getName()).second) { + this->m_error = { bitfieldNode->getLineNumber(), hex::format("Redeclaration of type '%s'", bitfieldNode->getName().c_str()) }; return false; + } size_t bitfieldSize = 0; // Check for duplicate constant names std::unordered_set flagNames; for (const auto &[name, size] : bitfieldNode->getFields()) { - if (!flagNames.insert(name).second) + if (!flagNames.insert(name).second) { + this->m_error = { bitfieldNode->getLineNumber(), hex::format("Redeclaration of member '%s'", name.c_str()) }; return false; + } bitfieldSize += size; } - if (bitfieldSize > 64) + if (bitfieldSize > 64) { + this->m_error = { bitfieldNode->getLineNumber(), "Bitfield exceeds maximum size of 64 bits" }; return false; + } } break; } diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 7d12b20fa..c4fa0b660 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -106,7 +106,7 @@ namespace hex { } return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); }); - preprocessor.addDefaultPragramHandlers(); + preprocessor.addDefaultPragmaHandlers(); std::error_code errorCode; @@ -234,6 +234,7 @@ namespace hex { void ViewPattern::parsePattern(char *buffer) { this->clearPatternData(); + this->m_textEditor.SetErrorMarkers({ }); this->postEvent(Events::PatternChanged); hex::lang::Preprocessor preprocessor; @@ -252,21 +253,25 @@ namespace hex { } else return false; }); - preprocessor.addDefaultPragramHandlers(); + preprocessor.addDefaultPragmaHandlers(); auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer); - if (preprocessingResult.failed()) + if (preprocessingResult.failed()) { + this->m_textEditor.SetErrorMarkers({ preprocessor.getError() }); return; + } hex::lang::Lexer lexer; auto [lexResult, tokens] = lexer.lex(preprocesedCode); if (lexResult.failed()) { + this->m_textEditor.SetErrorMarkers({ lexer.getError() }); return; } hex::lang::Parser parser; auto [parseResult, ast] = parser.parse(tokens); if (parseResult.failed()) { + this->m_textEditor.SetErrorMarkers({ parser.getError() }); return; } @@ -275,12 +280,14 @@ namespace hex { hex::lang::Validator validator; auto validatorResult = validator.validate(ast); if (!validatorResult) { + this->m_textEditor.SetErrorMarkers({ validator.getError() }); return; } hex::lang::Evaluator evaluator(this->m_dataProvider, dataEndianess); auto [evaluateResult, patternData] = evaluator.evaluate(ast); if (evaluateResult.failed()) { + this->m_textEditor.SetErrorMarkers({ evaluator.getError() }); return; } this->m_patternData = patternData;