Added attributes syntax to pattern language
This comes with two experimental attributes for variables called `name` and `color`
This commit is contained in:
parent
3e3a5273c0
commit
ff566aa51f
@ -9,6 +9,26 @@
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class ASTNodeAttribute;
|
||||
|
||||
class Attributable {
|
||||
protected:
|
||||
Attributable() = default;
|
||||
Attributable(const Attributable&) = default;
|
||||
public:
|
||||
|
||||
void addAttribute(ASTNodeAttribute *attribute) {
|
||||
this->m_attributes.push_back(attribute);
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto& getAttributes() const {
|
||||
return this->m_attributes;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ASTNodeAttribute*> m_attributes;
|
||||
};
|
||||
|
||||
class ASTNode {
|
||||
public:
|
||||
constexpr ASTNode() = default;
|
||||
@ -16,9 +36,9 @@ namespace hex::lang {
|
||||
constexpr ASTNode(const ASTNode &) = default;
|
||||
|
||||
[[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; }
|
||||
constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; }
|
||||
[[maybe_unused]] constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; }
|
||||
|
||||
virtual ASTNode* clone() const = 0;
|
||||
[[nodiscard]] virtual ASTNode* clone() const = 0;
|
||||
|
||||
private:
|
||||
u32 m_lineNumber = 1;
|
||||
@ -26,11 +46,11 @@ namespace hex::lang {
|
||||
|
||||
class ASTNodeIntegerLiteral : public ASTNode {
|
||||
public:
|
||||
ASTNodeIntegerLiteral(Token::IntegerLiteral literal) : ASTNode(), m_literal(literal) { }
|
||||
explicit ASTNodeIntegerLiteral(Token::IntegerLiteral literal) : ASTNode(), m_literal(std::move(literal)) { }
|
||||
|
||||
ASTNodeIntegerLiteral(const ASTNodeIntegerLiteral&) = default;
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeIntegerLiteral(*this);
|
||||
}
|
||||
|
||||
@ -62,7 +82,7 @@ namespace hex::lang {
|
||||
this->m_right = other.m_right->clone();
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeNumericExpression(*this);
|
||||
}
|
||||
|
||||
@ -93,7 +113,7 @@ namespace hex::lang {
|
||||
this->m_third = other.m_third->clone();
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeTernaryExpression(*this);
|
||||
}
|
||||
|
||||
@ -114,7 +134,7 @@ namespace hex::lang {
|
||||
|
||||
[[nodiscard]] constexpr const auto& getType() const { return this->m_type; }
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeBuiltinType(*this);
|
||||
}
|
||||
|
||||
@ -122,12 +142,12 @@ namespace hex::lang {
|
||||
const Token::ValueType m_type;
|
||||
};
|
||||
|
||||
class ASTNodeTypeDecl : public ASTNode {
|
||||
class ASTNodeTypeDecl : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeTypeDecl(std::string_view name, ASTNode *type, std::optional<std::endian> endian = { })
|
||||
: ASTNode(), m_name(name), m_type(type), m_endian(endian) { }
|
||||
|
||||
ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other) {
|
||||
ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_endian = other.m_endian;
|
||||
@ -137,7 +157,7 @@ namespace hex::lang {
|
||||
delete this->m_type;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeTypeDecl(*this);
|
||||
}
|
||||
|
||||
@ -151,12 +171,12 @@ namespace hex::lang {
|
||||
std::optional<std::endian> m_endian;
|
||||
};
|
||||
|
||||
class ASTNodeVariableDecl : public ASTNode {
|
||||
class ASTNodeVariableDecl : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeVariableDecl(std::string_view name, ASTNode *type, ASTNode *placementOffset = nullptr)
|
||||
: ASTNode(), m_name(name), m_type(type), m_placementOffset(placementOffset) { }
|
||||
|
||||
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other) {
|
||||
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
|
||||
@ -170,7 +190,7 @@ namespace hex::lang {
|
||||
delete this->m_type;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeVariableDecl(*this);
|
||||
}
|
||||
|
||||
@ -184,12 +204,12 @@ namespace hex::lang {
|
||||
ASTNode *m_placementOffset;
|
||||
};
|
||||
|
||||
class ASTNodeArrayVariableDecl : public ASTNode {
|
||||
class ASTNodeArrayVariableDecl : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeArrayVariableDecl(std::string_view name, ASTNode *type, ASTNode *size, ASTNode *placementOffset = nullptr)
|
||||
: ASTNode(), m_name(name), m_type(type), m_size(size), m_placementOffset(placementOffset) { }
|
||||
|
||||
ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other) {
|
||||
ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
if (other.m_size != nullptr)
|
||||
@ -208,7 +228,7 @@ namespace hex::lang {
|
||||
delete this->m_size;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeArrayVariableDecl(*this);
|
||||
}
|
||||
|
||||
@ -224,12 +244,12 @@ namespace hex::lang {
|
||||
ASTNode *m_placementOffset;
|
||||
};
|
||||
|
||||
class ASTNodePointerVariableDecl : public ASTNode {
|
||||
class ASTNodePointerVariableDecl : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodePointerVariableDecl(std::string_view name, ASTNode *type, ASTNode *sizeType, ASTNode *placementOffset = nullptr)
|
||||
: ASTNode(), m_name(name), m_type(type), m_sizeType(sizeType), m_placementOffset(placementOffset) { }
|
||||
|
||||
ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other) {
|
||||
ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_sizeType = other.m_sizeType->clone();
|
||||
@ -244,7 +264,7 @@ namespace hex::lang {
|
||||
delete this->m_type;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodePointerVariableDecl(*this);
|
||||
}
|
||||
|
||||
@ -260,11 +280,11 @@ namespace hex::lang {
|
||||
ASTNode *m_placementOffset;
|
||||
};
|
||||
|
||||
class ASTNodeStruct : public ASTNode {
|
||||
class ASTNodeStruct : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeStruct() : ASTNode() { }
|
||||
|
||||
ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other) {
|
||||
ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &otherMember : other.getMembers())
|
||||
this->m_members.push_back(otherMember->clone());
|
||||
}
|
||||
@ -274,7 +294,7 @@ namespace hex::lang {
|
||||
delete member;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeStruct(*this);
|
||||
}
|
||||
|
||||
@ -285,11 +305,11 @@ namespace hex::lang {
|
||||
std::vector<ASTNode*> m_members;
|
||||
};
|
||||
|
||||
class ASTNodeUnion : public ASTNode {
|
||||
class ASTNodeUnion : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeUnion() : ASTNode() { }
|
||||
|
||||
ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other) {
|
||||
ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &otherMember : other.getMembers())
|
||||
this->m_members.push_back(otherMember->clone());
|
||||
}
|
||||
@ -299,7 +319,7 @@ namespace hex::lang {
|
||||
delete member;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeUnion(*this);
|
||||
}
|
||||
|
||||
@ -310,11 +330,11 @@ namespace hex::lang {
|
||||
std::vector<ASTNode*> m_members;
|
||||
};
|
||||
|
||||
class ASTNodeEnum : public ASTNode {
|
||||
class ASTNodeEnum : public ASTNode, public Attributable {
|
||||
public:
|
||||
explicit ASTNodeEnum(ASTNode *underlyingType) : ASTNode(), m_underlyingType(underlyingType) { }
|
||||
|
||||
ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other) {
|
||||
ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &[name, entry] : other.getEntries())
|
||||
this->m_entries.insert({ name, entry->clone() });
|
||||
this->m_underlyingType = other.m_underlyingType->clone();
|
||||
@ -326,7 +346,7 @@ namespace hex::lang {
|
||||
delete this->m_underlyingType;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeEnum(*this);
|
||||
}
|
||||
|
||||
@ -340,11 +360,11 @@ namespace hex::lang {
|
||||
ASTNode *m_underlyingType;
|
||||
};
|
||||
|
||||
class ASTNodeBitfield : public ASTNode {
|
||||
class ASTNodeBitfield : public ASTNode, public Attributable {
|
||||
public:
|
||||
ASTNodeBitfield() : ASTNode() { }
|
||||
|
||||
ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other) {
|
||||
ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &[name, entry] : other.getEntries())
|
||||
this->m_entries.emplace_back(name, entry->clone());
|
||||
}
|
||||
@ -354,7 +374,7 @@ namespace hex::lang {
|
||||
delete expr;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeBitfield(*this);
|
||||
}
|
||||
|
||||
@ -371,7 +391,7 @@ namespace hex::lang {
|
||||
|
||||
ASTNodeRValue(const ASTNodeRValue&) = default;
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeRValue(*this);
|
||||
}
|
||||
|
||||
@ -389,7 +409,7 @@ namespace hex::lang {
|
||||
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution&) = default;
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeScopeResolution(*this);
|
||||
}
|
||||
|
||||
@ -424,7 +444,7 @@ namespace hex::lang {
|
||||
this->m_falseBody.push_back(statement->clone());
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeConditionalStatement(*this);
|
||||
}
|
||||
|
||||
@ -462,7 +482,7 @@ namespace hex::lang {
|
||||
this->m_params.push_back(param->clone());
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeFunctionCall(*this);
|
||||
}
|
||||
|
||||
@ -483,13 +503,13 @@ namespace hex::lang {
|
||||
public:
|
||||
explicit ASTNodeStringLiteral(std::string_view string) : ASTNode(), m_string(string) { }
|
||||
|
||||
~ASTNodeStringLiteral() override { }
|
||||
~ASTNodeStringLiteral() override = default;
|
||||
|
||||
ASTNodeStringLiteral(const ASTNodeStringLiteral &other) : ASTNode(other) {
|
||||
this->m_string = other.m_string;
|
||||
}
|
||||
|
||||
ASTNode* clone() const override {
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeStringLiteral(*this);
|
||||
}
|
||||
|
||||
@ -501,5 +521,32 @@ namespace hex::lang {
|
||||
std::string m_string;
|
||||
};
|
||||
|
||||
class ASTNodeAttribute : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeAttribute(std::string_view attribute, std::string_view value = { })
|
||||
: ASTNode(), m_attribute(attribute), m_value(value) { }
|
||||
|
||||
~ASTNodeAttribute() override = default;
|
||||
|
||||
ASTNodeAttribute(const ASTNodeAttribute &other) : ASTNode(other) {
|
||||
this->m_attribute = other.m_attribute;
|
||||
this->m_value = other.m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeAttribute(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view getAttribute() const {
|
||||
return this->m_attribute;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view getValue() const {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_attribute, m_value;
|
||||
};
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ namespace hex::lang {
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] static void abortEvaluation(std::string_view message) {
|
||||
[[noreturn]] void abortEvaluation(std::string_view message) {
|
||||
throw EvaluateError(message);
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ namespace hex::lang {
|
||||
|
||||
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
|
||||
auto& getConsole() { return this->m_console; }
|
||||
LogConsole& getConsole() { return this->m_console; }
|
||||
|
||||
private:
|
||||
std::map<std::string, ASTNode*> m_types;
|
||||
@ -76,6 +76,7 @@ namespace hex::lang {
|
||||
ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node);
|
||||
|
||||
PatternData* patternFromName(const std::vector<std::string> &name);
|
||||
PatternData* evaluateAttributes(ASTNode *currNode, PatternData *currPattern);
|
||||
PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node);
|
||||
void evaluateMember(ASTNode *node, std::vector<PatternData*> &currMembers, bool increaseOffset);
|
||||
PatternData* evaluateStruct(ASTNodeStruct *node);
|
||||
|
@ -71,6 +71,7 @@ namespace hex::lang {
|
||||
ASTNode* parseTernaryConditional();
|
||||
ASTNode* parseMathematicalExpression();
|
||||
|
||||
void parseAttribute(Attributable *currNode);
|
||||
ASTNode* parseConditional();
|
||||
ASTNode* parseType(s32 startIndex);
|
||||
ASTNode* parseUsingDeclaration();
|
||||
|
@ -331,6 +331,47 @@ namespace hex::lang {
|
||||
return evaluateOperator(leftInteger, rightInteger, node->getOperator());
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateAttributes(ASTNode *currNode, PatternData *currPattern) {
|
||||
auto attributableNode = dynamic_cast<Attributable*>(currNode);
|
||||
if (attributableNode == nullptr)
|
||||
this->getConsole().abortEvaluation("attributes applied to invalid expression");
|
||||
|
||||
auto handleVariableAttributes = [this, &currPattern](auto attribute, auto value) {
|
||||
|
||||
if (attribute == "color")
|
||||
currPattern->setColor(strtoul(value.data(), nullptr, 0));
|
||||
else if (attribute == "name")
|
||||
currPattern->setVariableName(value.data());
|
||||
else
|
||||
this->getConsole().abortEvaluation("unknown or invalid attribute");
|
||||
|
||||
};
|
||||
|
||||
auto &attributes = attributableNode->getAttributes();
|
||||
|
||||
if (auto variableDeclNode = dynamic_cast<ASTNodeVariableDecl*>(currNode); variableDeclNode != nullptr) {
|
||||
for (auto &attribute : attributes)
|
||||
handleVariableAttributes(attribute->getAttribute(), attribute->getValue());
|
||||
} else if (auto arrayDeclNode = dynamic_cast<ASTNodeArrayVariableDecl*>(currNode); arrayDeclNode != nullptr) {
|
||||
for (auto &attribute : attributes)
|
||||
handleVariableAttributes(attribute->getAttribute(), attribute->getValue());
|
||||
} else if (auto pointerDeclNode = dynamic_cast<ASTNodePointerVariableDecl*>(currNode); pointerDeclNode != nullptr) {
|
||||
for (auto &attribute : attributes)
|
||||
handleVariableAttributes(attribute->getAttribute(), attribute->getValue());
|
||||
} else if (auto structNode = dynamic_cast<ASTNodeStruct*>(currNode); structNode != nullptr) {
|
||||
this->getConsole().abortEvaluation("unknown or invalid attribute");
|
||||
} else if (auto unionNode = dynamic_cast<ASTNodeUnion*>(currNode); unionNode != nullptr) {
|
||||
this->getConsole().abortEvaluation("unknown or invalid attribute");
|
||||
} else if (auto enumNode = dynamic_cast<ASTNodeEnum*>(currNode); enumNode != nullptr) {
|
||||
this->getConsole().abortEvaluation("unknown or invalid attribute");
|
||||
} else if (auto bitfieldNode = dynamic_cast<ASTNodeBitfield*>(currNode); bitfieldNode != nullptr) {
|
||||
this->getConsole().abortEvaluation("unknown or invalid attribute");
|
||||
} else
|
||||
this->getConsole().abortEvaluation("attributes applied to invalid expression");
|
||||
|
||||
return currPattern;
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateBuiltinType(ASTNodeBuiltinType *node) {
|
||||
auto &type = node->getType();
|
||||
auto typeSize = Token::getTypeSize(type);
|
||||
@ -400,7 +441,7 @@ namespace hex::lang {
|
||||
this->evaluateMember(member, memberPatterns, true);
|
||||
}
|
||||
|
||||
return new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns);
|
||||
return this->evaluateAttributes(node, new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns));
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateUnion(ASTNodeUnion *node) {
|
||||
@ -421,7 +462,7 @@ namespace hex::lang {
|
||||
|
||||
this->m_currOffset += size;
|
||||
|
||||
return new PatternDataUnion(startOffset, size, memberPatterns);
|
||||
return this->evaluateAttributes(node, new PatternDataUnion(startOffset, size, memberPatterns));
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateEnum(ASTNodeEnum *node) {
|
||||
@ -451,7 +492,7 @@ namespace hex::lang {
|
||||
|
||||
this->m_currOffset += size;
|
||||
|
||||
return new PatternDataEnum(startOffset, size, entryPatterns);;
|
||||
return this->evaluateAttributes(node, new PatternDataEnum(startOffset, size, entryPatterns));
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) {
|
||||
@ -484,7 +525,7 @@ namespace hex::lang {
|
||||
size_t size = (bits + 7) / 8;
|
||||
this->m_currOffset += size;
|
||||
|
||||
return new PatternDataBitfield(startOffset, size, entryPatterns);
|
||||
return this->evaluateAttributes(node, new PatternDataBitfield(startOffset, size, entryPatterns));
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateType(ASTNodeTypeDecl *node) {
|
||||
@ -544,7 +585,7 @@ namespace hex::lang {
|
||||
|
||||
pattern->setVariableName(node->getName().data());
|
||||
|
||||
return pattern;
|
||||
return this->evaluateAttributes(node, pattern);
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateArray(ASTNodeArrayVariableDecl *node) {
|
||||
@ -637,7 +678,7 @@ namespace hex::lang {
|
||||
|
||||
pattern->setVariableName(node->getName().data());
|
||||
|
||||
return pattern;
|
||||
return this->evaluateAttributes(node, pattern);
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluatePointer(ASTNodePointerVariableDecl *node) {
|
||||
@ -694,7 +735,7 @@ namespace hex::lang {
|
||||
pattern->setVariableName(node->getName().data());
|
||||
pattern->setEndian(this->getCurrentEndian());
|
||||
|
||||
return pattern;
|
||||
return this->evaluateAttributes(node, pattern);
|
||||
}
|
||||
|
||||
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
|
||||
|
@ -262,6 +262,29 @@ namespace hex::lang {
|
||||
return this->parseTernaryConditional();
|
||||
}
|
||||
|
||||
// [[ <Identifier[( (parseStringLiteral) )], ...> ]]
|
||||
void Parser::parseAttribute(Attributable *currNode) {
|
||||
if (currNode == nullptr)
|
||||
throwParseError("tried to apply attribute to invalid statement");
|
||||
|
||||
do {
|
||||
if (!MATCHES(sequence(IDENTIFIER)))
|
||||
throwParseError("expected attribute expression");
|
||||
|
||||
auto attribute = this->getValue<std::string>(-1);
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN, STRING, SEPARATOR_ROUNDBRACKETCLOSE))) {
|
||||
auto value = this->getValue<std::string>(-2);
|
||||
currNode->addAttribute(new ASTNodeAttribute(attribute, value));
|
||||
}
|
||||
else
|
||||
currNode->addAttribute(new ASTNodeAttribute(attribute));
|
||||
|
||||
} while (MATCHES(sequence(SEPARATOR_COMMA)));
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE, SEPARATOR_SQUAREBRACKETCLOSE)))
|
||||
throwParseError("unfinished attribute. Expected ']]'");
|
||||
}
|
||||
|
||||
/* Control flow */
|
||||
|
||||
@ -410,6 +433,9 @@ namespace hex::lang {
|
||||
else
|
||||
throwParseError("invalid struct member", 0);
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN)))
|
||||
parseAttribute(dynamic_cast<Attributable *>(member));
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
|
||||
throwParseError("missing ';' at end of expression", -1);
|
||||
|
||||
@ -605,6 +631,9 @@ namespace hex::lang {
|
||||
statement = parseFunctionCall();
|
||||
else throwParseError("invalid sequence", 0);
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN)))
|
||||
parseAttribute(dynamic_cast<Attributable *>(statement));
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
|
||||
throwParseError("missing ';' at end of expression", -1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user