Implements basic virtprop parsing.
This commit is contained in:
parent
6a0ec63a7e
commit
823b00777e
|
@ -8,6 +8,7 @@ namespace MalachScript::Diagnostics {
|
||||||
InvalidNumericalBase,
|
InvalidNumericalBase,
|
||||||
ExpectedEndOfString,
|
ExpectedEndOfString,
|
||||||
UnexpectedToken,
|
UnexpectedToken,
|
||||||
|
DoubleProperty,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiagnosticTypeHelper {
|
class DiagnosticTypeHelper {
|
||||||
|
@ -17,6 +18,7 @@ namespace MalachScript::Diagnostics {
|
||||||
case DiagnosticType::InvalidNumericalBase: return "Invalid numerical base";
|
case DiagnosticType::InvalidNumericalBase: return "Invalid numerical base";
|
||||||
case DiagnosticType::ExpectedEndOfString: return "Expected end of string";
|
case DiagnosticType::ExpectedEndOfString: return "Expected end of string";
|
||||||
case DiagnosticType::UnexpectedToken: return "Unexpected Token";
|
case DiagnosticType::UnexpectedToken: return "Unexpected Token";
|
||||||
|
case DiagnosticType::DoubleProperty: return "Property block found twice.";
|
||||||
}
|
}
|
||||||
return std::to_string((uint8_t)type);
|
return std::to_string((uint8_t)type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../CoreData/FuncAttr.hpp"
|
|
||||||
#include "../CoreData/PrimitiveTypes.hpp"
|
#include "../CoreData/PrimitiveTypes.hpp"
|
||||||
|
|
||||||
#define PROGRESS_TOKEN(token) \
|
#define PROGRESS_TOKEN(token) \
|
||||||
|
@ -104,10 +103,11 @@ namespace MalachScript::Parser {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const ParsedStatement* statement = nullptr;
|
const ParsedStatement* statement = nullptr;
|
||||||
// TODO: Sort by
|
// TODO: Sort by complexity
|
||||||
if (!ParseVirtProp(statement) && !ParseFunc(statement) && !ParseVar(statement) &&
|
if (!ParseVirtProp(statement, current) && !ParseFunc(statement) && !ParseVar(statement) &&
|
||||||
!ParseFuncDef(statement)) {
|
!ParseFuncDef(statement)) {
|
||||||
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
body.push_back(statement);
|
body.push_back(statement);
|
||||||
}
|
}
|
||||||
|
@ -211,29 +211,8 @@ namespace MalachScript::Parser {
|
||||||
isConst = true;
|
isConst = true;
|
||||||
PROGRESS_TOKEN(_currentToken);
|
PROGRESS_TOKEN(_currentToken);
|
||||||
}
|
}
|
||||||
bool lookingForFuncAttr = true;
|
|
||||||
FuncAttr funcAttr = FuncAttr::None;
|
FuncAttr funcAttr = FuncAttr::None;
|
||||||
while (lookingForFuncAttr) {
|
ParseFuncAttr(funcAttr, _currentToken);
|
||||||
switch (_currentToken->GetKind()) {
|
|
||||||
case LexTokenKind::OverrideKeyword:
|
|
||||||
PROGRESS_TOKEN(_currentToken);
|
|
||||||
funcAttr = FuncAttrHelpers::Set(funcAttr, FuncAttr::Override);
|
|
||||||
continue;
|
|
||||||
case LexTokenKind::FinalKeyword:
|
|
||||||
PROGRESS_TOKEN(_currentToken);
|
|
||||||
funcAttr = FuncAttrHelpers::Set(funcAttr, FuncAttr::Final);
|
|
||||||
continue;
|
|
||||||
case LexTokenKind::ExplicitKeyword:
|
|
||||||
PROGRESS_TOKEN(_currentToken);
|
|
||||||
funcAttr = FuncAttrHelpers::Set(funcAttr, FuncAttr::Explicit);
|
|
||||||
continue;
|
|
||||||
case LexTokenKind::PropertyKeyword:
|
|
||||||
PROGRESS_TOKEN(_currentToken);
|
|
||||||
funcAttr = FuncAttrHelpers::Set(funcAttr, FuncAttr::Property);
|
|
||||||
continue;
|
|
||||||
default: lookingForFuncAttr = false; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const ParsedStatement* statblock = nullptr;
|
const ParsedStatement* statblock = nullptr;
|
||||||
if (_currentToken->GetKind() != LexTokenKind::SemicolonSymbol) {
|
if (_currentToken->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||||
// TODO: Parse stat block.
|
// TODO: Parse stat block.
|
||||||
|
@ -317,6 +296,34 @@ namespace MalachScript::Parser {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken) {
|
||||||
|
bool lookingForFuncAttr = true;
|
||||||
|
const auto* current = currentToken;
|
||||||
|
while (lookingForFuncAttr) {
|
||||||
|
switch (current->GetKind()) {
|
||||||
|
case LexTokenKind::OverrideKeyword:
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
out = FuncAttrHelpers::Set(out, FuncAttr::Override);
|
||||||
|
continue;
|
||||||
|
case LexTokenKind::FinalKeyword:
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
out = FuncAttrHelpers::Set(out, FuncAttr::Final);
|
||||||
|
continue;
|
||||||
|
case LexTokenKind::ExplicitKeyword:
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
out = FuncAttrHelpers::Set(out, FuncAttr::Explicit);
|
||||||
|
continue;
|
||||||
|
case LexTokenKind::PropertyKeyword:
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
out = FuncAttrHelpers::Set(out, FuncAttr::Property);
|
||||||
|
continue;
|
||||||
|
default: lookingForFuncAttr = false; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_currentToken = current;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Parser::ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken) {
|
bool Parser::ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken) {
|
||||||
if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) {
|
if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -333,7 +340,8 @@ namespace MalachScript::Parser {
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
||||||
return true;
|
return true;
|
||||||
} if (currentToken->GetKind() == LexTokenKind::CloseParenthesisSymbol) {
|
}
|
||||||
|
if (currentToken->GetKind() == LexTokenKind::CloseParenthesisSymbol) {
|
||||||
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
return true;
|
return true;
|
||||||
|
@ -396,7 +404,105 @@ namespace MalachScript::Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::ParseVirtProp([[maybe_unused]] const ParsedStatement*& out) { return false; }
|
bool Parser::ParseVirtProp([[maybe_unused]] const ParsedStatement*& out, const LexToken*& currentToken) {
|
||||||
|
AccessModifier access = AccessModifier::Public;
|
||||||
|
const auto* current = currentToken;
|
||||||
|
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
|
||||||
|
access = AccessModifier::Private;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
|
||||||
|
access = AccessModifier::Protected;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
}
|
||||||
|
const ParsedStatement* typeStatement = nullptr;
|
||||||
|
if (!ParseType(typeStatement, current)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool ref = false;
|
||||||
|
if (current->GetKind() == LexTokenKind::AmpersandSymbol) {
|
||||||
|
ref = true;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
}
|
||||||
|
Identifier identifier;
|
||||||
|
if (!ParseIdentifier(identifier, current)) {
|
||||||
|
delete typeStatement;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool hasGet = false;
|
||||||
|
bool getConst = false;
|
||||||
|
FuncAttr getAttr = FuncAttr::None;
|
||||||
|
const ParsedStatement* getStatement = nullptr;
|
||||||
|
bool hasSet = false;
|
||||||
|
bool setConst = false;
|
||||||
|
FuncAttr setAttr = FuncAttr::None;
|
||||||
|
const ParsedStatement* setStatement = nullptr;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
while (true) {
|
||||||
|
auto start = current->GetSpan().GetStart();
|
||||||
|
if (current->GetKind() == LexTokenKind::GetKeyword) {
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
||||||
|
getConst = true;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
}
|
||||||
|
ParseFuncAttr(getAttr, current);
|
||||||
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||||
|
// TODO: Parse stat block.
|
||||||
|
// if (ParseStatBlock(getStatement, current)){
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
}
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
|
||||||
|
if (hasGet) {
|
||||||
|
this->LogError(Diagnostics::DiagnosticType::DoubleProperty,
|
||||||
|
TextSpan(start, current->GetSpan().GetEnd()));
|
||||||
|
}
|
||||||
|
hasGet = true;
|
||||||
|
} else if (current->GetKind() == LexTokenKind::SetKeyword) {
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
||||||
|
setConst = true;
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
}
|
||||||
|
ParseFuncAttr(setAttr, current);
|
||||||
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||||
|
// TODO: Parse stat block.
|
||||||
|
// if (ParseStatBlock(setStatement, current)){
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
}
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
|
||||||
|
if (hasSet) {
|
||||||
|
this->LogError(Diagnostics::DiagnosticType::DoubleProperty,
|
||||||
|
TextSpan(start, current->GetSpan().GetEnd()));
|
||||||
|
}
|
||||||
|
hasSet = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol){
|
||||||
|
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
PROGRESS_TOKEN(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
out = new ParsedVirtPropStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
|
||||||
|
access, typeStatement, ref, identifier, hasGet, getConst, getAttr,
|
||||||
|
getStatement, hasSet, setConst, setAttr, setStatement);
|
||||||
|
currentToken = current;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Parser::ParseVar([[maybe_unused]] const ParsedStatement*& out) { return false; }
|
bool Parser::ParseVar([[maybe_unused]] const ParsedStatement*& out) { return false; }
|
||||||
bool Parser::ParseFuncDef([[maybe_unused]] const ParsedStatement*& out) { return false; }
|
bool Parser::ParseFuncDef([[maybe_unused]] const ParsedStatement*& out) { return false; }
|
||||||
bool Parser::ParsePrimType(Identifier& out, const LexToken*& token) {
|
bool Parser::ParsePrimType(Identifier& out, const LexToken*& token) {
|
||||||
|
|
|
@ -28,11 +28,12 @@ namespace MalachScript::Parser {
|
||||||
|
|
||||||
bool ParseType(const ParsedStatement*& out, const LexToken*& currentToken);
|
bool ParseType(const ParsedStatement*& out, const LexToken*& currentToken);
|
||||||
bool ParseScope(std::vector<Identifier>& out, const LexToken*& currentToken);
|
bool ParseScope(std::vector<Identifier>& out, const LexToken*& currentToken);
|
||||||
|
bool ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken);
|
||||||
bool ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken);
|
bool ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken);
|
||||||
bool ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken);
|
bool ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken);
|
||||||
bool ParseDataType(Identifier& out, const LexToken*& currentToken);
|
bool ParseDataType(Identifier& out, const LexToken*& currentToken);
|
||||||
|
|
||||||
bool ParseVirtProp(const ParsedStatement*& out);
|
bool ParseVirtProp(const ParsedStatement*& out, const LexToken*& currentToken);
|
||||||
bool ParseVar(const ParsedStatement*& out);
|
bool ParseVar(const ParsedStatement*& out);
|
||||||
bool ParseFuncDef(const ParsedStatement*& out);
|
bool ParseFuncDef(const ParsedStatement*& out);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,12 @@ namespace MalachScript::Parser {
|
||||||
for (size_t i = 0; i < body.size(); i++)
|
for (size_t i = 0; i < body.size(); i++)
|
||||||
_body[i] = std::unique_ptr<const ParsedStatement>(body[i]);
|
_body[i] = std::unique_ptr<const ParsedStatement>(body[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const Identifier& GetIdentifier() const noexcept { return _identifier; }
|
||||||
|
[[nodiscard]] const std::vector<Identifier>& GetInherits() const noexcept { return _inherits; }
|
||||||
|
[[nodiscard]] const std::vector<std::unique_ptr<const ParsedStatement>>& GetBody() const noexcept {
|
||||||
|
return _body;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedTypeDefStatement : public ParsedStatementImpl<ParsedStatementKind::TypeDef> {
|
class ParsedTypeDefStatement : public ParsedStatementImpl<ParsedStatementKind::TypeDef> {
|
||||||
|
@ -192,6 +198,48 @@ namespace MalachScript::Parser {
|
||||||
return _statBlock;
|
return _statBlock;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParsedVirtPropStatement : public ParsedStatementImpl<ParsedStatementKind::VirtProp> {
|
||||||
|
public:
|
||||||
|
ParsedVirtPropStatement(const TextSpan& span, AccessModifier access, const ParsedStatement* returnType,
|
||||||
|
bool isReturnTypeRef, Identifier identifier, bool hasGet, bool getConst,
|
||||||
|
FuncAttr getAttr, const ParsedStatement* getStatement, bool hasSet, bool setConst,
|
||||||
|
FuncAttr setAttr, const ParsedStatement* setStatement)
|
||||||
|
: ParsedStatementImpl(span), _access(access), _returnType(returnType), _isReturnTypeRef(isReturnTypeRef),
|
||||||
|
_identifier(identifier), _hasGet(hasGet), _getConst(getConst), _getAttr(getAttr),
|
||||||
|
_getStatement(getStatement), _hasSet(hasSet), _setConst(setConst), _setAttr(setAttr),
|
||||||
|
_setStatement(setStatement) {}
|
||||||
|
|
||||||
|
[[nodiscard]] inline AccessModifier GetAccess() const noexcept { return _access; }
|
||||||
|
[[nodiscard]] inline const ParsedStatement* GetReturnType() const noexcept { return _returnType; }
|
||||||
|
[[nodiscard]] inline bool IsReturnTypeRef() const noexcept { return _isReturnTypeRef; }
|
||||||
|
[[nodiscard]] inline const Identifier& GetIdentifier() const noexcept { return _identifier; }
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool HasGet() const noexcept { return _hasGet; }
|
||||||
|
[[nodiscard]] inline bool IsGetConst() const noexcept { return _getConst; }
|
||||||
|
[[nodiscard]] inline FuncAttr GetGetFuncAttr() const noexcept { return _getAttr; }
|
||||||
|
[[nodiscard]] inline const ParsedStatement* GetGetStatement() const noexcept { return _getStatement; }
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool HasSet() const noexcept { return _hasSet; }
|
||||||
|
[[nodiscard]] inline bool IsSetConst() const noexcept { return _setConst; }
|
||||||
|
[[nodiscard]] inline FuncAttr GetSetFuncAttr() const noexcept { return _setAttr; }
|
||||||
|
[[nodiscard]] inline const ParsedStatement* GetSetStatement() const noexcept { return _setStatement; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AccessModifier _access;
|
||||||
|
const ParsedStatement* _returnType;
|
||||||
|
bool _isReturnTypeRef;
|
||||||
|
Identifier _identifier;
|
||||||
|
|
||||||
|
bool _hasGet = false;
|
||||||
|
bool _getConst = false;
|
||||||
|
FuncAttr _getAttr = FuncAttr::None;
|
||||||
|
const ParsedStatement* _getStatement;
|
||||||
|
bool _hasSet = false;
|
||||||
|
bool _setConst = false;
|
||||||
|
FuncAttr _setAttr = FuncAttr::None;
|
||||||
|
const ParsedStatement* _setStatement;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
#endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace MalachScript::Parser {
|
||||||
Type,
|
Type,
|
||||||
ParamList,
|
ParamList,
|
||||||
Func,
|
Func,
|
||||||
|
VirtProp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,3 +32,15 @@ PARSE_TEST("Parse function without definition", "void foobar(int8 par1, bool &in
|
||||||
REQUIRE(script->GetStatements().size() == 1);
|
REQUIRE(script->GetStatements().size() == 1);
|
||||||
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
|
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
PARSE_TEST("Parse class with virtprop", "class foobar { private bool foo { get; set; } }", {
|
||||||
|
REQUIRE(diags.GetMessages().empty());
|
||||||
|
REQUIRE(script->GetStatements().size() == 1);
|
||||||
|
auto firstStatement = script->GetStatements()[0].get();
|
||||||
|
REQUIRE(firstStatement->GetKind() == Parser::ParsedStatementKind::Class);
|
||||||
|
auto firstClassStatement = dynamic_cast<const MalachScript::Parser::ParsedClassStatement*>(firstStatement)->GetBody()[0].get();
|
||||||
|
REQUIRE(firstClassStatement->GetKind() == Parser::ParsedStatementKind::VirtProp);
|
||||||
|
auto virtPropStatement = dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
|
||||||
|
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Private);
|
||||||
|
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo");
|
||||||
|
})
|
Loading…
Reference in New Issue