1
0
mirror of synced 2024-11-12 02:00:52 +01:00

Added error messages and error display to pattern language editor

This commit is contained in:
WerWolv 2020-11-27 21:20:23 +01:00
parent d55bea7c46
commit 3827919a32
13 changed files with 329 additions and 138 deletions

View File

@ -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<u64> offset = { }, size_t arraySize = 1, std::optional<std::string> arraySizeVariable = { }, std::optional<u8> 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<u64> offset = { }, size_t arraySize = 1, std::optional<std::string> arraySizeVariable = { }, std::optional<u8> 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<ASTNode*> nodes) : ASTNode(Type::Scope), m_nodes(nodes) { }
explicit ASTNodeScope(u32 lineNumber, std::vector<ASTNode*> nodes) : ASTNode(Type::Scope, lineNumber), m_nodes(nodes) { }
std::vector<ASTNode*> &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<ASTNode*> nodes)
: ASTNode(Type::Struct), m_name(name), m_nodes(nodes) { }
explicit ASTNodeStruct(u32 lineNumber, std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Struct, lineNumber), m_name(name), m_nodes(nodes) { }
const std::string& getName() const { return this->m_name; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
@ -74,8 +76,8 @@ namespace hex::lang {
class ASTNodeUnion : public ASTNode {
public:
explicit ASTNodeUnion(std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Union), m_name(name), m_nodes(nodes) { }
explicit ASTNodeUnion(u32 lineNumber, std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Union, lineNumber), m_name(name), m_nodes(nodes) { }
const std::string& getName() const { return this->m_name; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
@ -86,8 +88,8 @@ namespace hex::lang {
class ASTNodeBitField : public ASTNode {
public:
explicit ASTNodeBitField(std::string name, std::vector<std::pair<std::string, size_t>> fields)
: ASTNode(Type::Bitfield), m_name(name), m_fields(fields) { }
explicit ASTNodeBitField(u32 lineNumber, std::string name, std::vector<std::pair<std::string, size_t>> fields)
: ASTNode(Type::Bitfield, lineNumber), m_name(name), m_fields(fields) { }
const std::string& getName() const { return this->m_name; }
std::vector<std::pair<std::string, size_t>> &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; };

View File

@ -19,11 +19,14 @@ namespace hex::lang {
std::pair<Result, std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::unordered_map<std::string, ASTNode*> m_types;
prv::Provider* &m_provider;
std::endian m_dataEndianess;
std::pair<u32, std::string> m_error;
std::pair<PatternData*, size_t> createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);

View File

@ -14,6 +14,11 @@ namespace hex::lang {
Lexer();
std::pair<Result, std::vector<Token>> lex(const std::string& code);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> m_error;
};
}

View File

@ -12,8 +12,37 @@ namespace hex::lang {
public:
Parser();
using TokenIter = std::vector<Token>::const_iterator;
std::pair<Result, std::vector<ASTNode*>> parse(const std::vector<Token> &tokens);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> 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<ASTNode*> parseUsingDeclaration(TokenIter &curr);
std::optional<std::vector<ASTNode*>> parseStatement(TokenIter &curr);
std::vector<ASTNode*> parseTillToken(TokenIter &curr, Token::Type endTokenType);
bool tryConsume(TokenIter &curr, std::initializer_list<Token::Type> tokenTypes);
};
}

View File

@ -19,13 +19,17 @@ namespace hex::lang {
std::pair<Result, std::string> preprocess(const std::string& code, bool initialRun = true);
void addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function);
void addDefaultPragramHandlers();
void addDefaultPragmaHandlers();
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
std::set<std::pair<std::string, std::string>> m_defines;
std::set<std::pair<std::string, std::string>> m_pragmas;
std::pair<u32, std::string> m_error;
};
}

View File

@ -63,5 +63,7 @@ namespace hex::lang {
Padding = 0x1F
} type;
} typeToken;
u32 lineNumber;
};
}

View File

@ -15,6 +15,11 @@ namespace hex::lang {
Validator();
bool validate(const std::vector<ASTNode*>& ast);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> m_error;
};
}

View File

@ -14,8 +14,10 @@ namespace hex::lang {
auto structNode = static_cast<ASTNodeStruct*>(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<ASTNodeUnion*>(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<PatternData*, size_t> Evaluator::createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<std::pair<u64, std::string>> enumValues;
auto *enumType = static_cast<ASTNodeEnum*>(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<ASTNodeBitField*>(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<u32> 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<PatternData*, size_t> 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<ASTNodeTypeDecl*>(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();
}

View File

@ -69,6 +69,8 @@ namespace hex::lang {
std::vector<Token> 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 };
}

View File

@ -10,11 +10,7 @@ namespace hex::lang {
}
using TokenIter = std::vector<Token>::const_iterator;
std::vector<ASTNode*> parseTillToken(TokenIter &curr, Token::Type endTokenType);
bool tryConsume(TokenIter &curr, std::initializer_list<Token::Type> tokenTypes) {
bool Parser::tryConsume(TokenIter &curr, std::initializer_list<Token::Type> tokenTypes) {
std::vector<Token>::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<ASTNode*> 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<ASTNode*> 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<u32>(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<std::pair<std::string, size_t>> 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<ASTNode*> parseUsingDeclaration(TokenIter &curr) {
std::optional<ASTNode*> 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<std::vector<ASTNode*>> parseStatement(TokenIter &curr) {
std::optional<std::vector<ASTNode*>> Parser::parseStatement(TokenIter &curr) {
std::vector<ASTNode*> 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<ASTNode*> parseTillToken(TokenIter &curr, Token::Type endTokenType) {
std::vector<ASTNode*> Parser::parseTillToken(TokenIter &curr, Token::Type endTokenType) {
std::vector<ASTNode*> program;
while (curr->type != endTokenType) {

View File

@ -8,6 +8,7 @@ namespace hex::lang {
std::pair<Result, std::string> 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');
});

View File

@ -3,6 +3,8 @@
#include <unordered_set>
#include <string>
#include "utils.hpp"
namespace hex::lang {
Validator::Validator() {
@ -19,73 +21,96 @@ namespace hex::lang {
{
// Check for duplicate variable names
auto varDeclNode = static_cast<ASTNodeVariableDecl*>(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<ASTNodeTypeDecl*>(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<ASTNodeStruct*>(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<std::string> memberNames;
for (const auto &member : structNode->getNodes())
if (!memberNames.insert(static_cast<ASTNodeVariableDecl*>(member)->getVariableName()).second)
if (!memberNames.insert(static_cast<ASTNodeVariableDecl*>(member)->getVariableName()).second) {
this->m_error = { member->getLineNumber(), hex::format("Redeclaration of member '%s'", static_cast<ASTNodeVariableDecl*>(member)->getVariableName().c_str()) };
return false;
}
}
break;
case ASTNode::Type::Enum:
{
// Check for duplicate type name
auto enumNode = static_cast<ASTNodeEnum*>(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<std::string> 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<ASTNodeBitField*>(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<std::string> 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;
}

View File

@ -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;