Added error messages and error display to pattern language editor
This commit is contained in:
parent
d55bea7c46
commit
3827919a32
@ -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; };
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -63,5 +63,7 @@ namespace hex::lang {
|
||||
Padding = 0x1F
|
||||
} type;
|
||||
} typeToken;
|
||||
|
||||
u32 lineNumber;
|
||||
};
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user