Support basic parsing function statements.

This commit is contained in:
Deukhoofd 2020-10-10 14:29:37 +02:00
parent 911be3f2ed
commit dcf143b1b2
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
12 changed files with 505 additions and 46 deletions

View File

@ -0,0 +1,9 @@
#ifndef MALACHSCRIPT_ACCESSMODIFIER_HPP
#define MALACHSCRIPT_ACCESSMODIFIER_HPP
#include <cstdint>
namespace MalachScript {
enum class AccessModifier : uint8_t { Public, Private, Protected };
}
#endif // MALACHSCRIPT_ACCESSMODIFIER_HPP

25
src/CoreData/FuncAttr.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef MALACHSCRIPT_FUNCATTR_HPP
#define MALACHSCRIPT_FUNCATTR_HPP
#include <cstdint>
namespace MalachScript {
enum class FuncAttr : uint8_t {
None = 0,
Override = 1 << 1,
Final = 1 << 2,
Explicit = 1 << 3,
Property = 1 << 4,
};
class FuncAttrHelpers {
public:
constexpr inline static bool Contains(FuncAttr set, FuncAttr flag) {
return (static_cast<uint8_t>(set) & static_cast<uint8_t>(flag)) != 0;
}
constexpr inline static FuncAttr Set(FuncAttr set, FuncAttr flag){
return static_cast<FuncAttr>(static_cast<uint8_t>(set) | static_cast<uint8_t>(flag));
}
};
}
#endif // MALACHSCRIPT_FUNCATTR_HPP

View File

@ -36,13 +36,15 @@ namespace MalachScript {
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
static std::u8string empty;
class Identifier {
std::u8string_view _str;
uint32_t _hash;
public:
Identifier() : _hash(0) {}
consteval Identifier(const char8_t* c) : _str(c), _hash(Hash(c)) {}
Identifier() : _str(empty), _hash(0) {}
constexpr Identifier(const char8_t* c) : _str(c), _hash(Hash(c)) {}
Identifier(const std::u8string_view& c) : _str(c), _hash(Hash(c)) {}
Identifier(const std::u8string_view& c, uint32_t hash) : _str(c), _hash(hash) {}
@ -59,6 +61,19 @@ namespace MalachScript {
private:
};
class ScopedIdentifier {
std::vector<Identifier> _scope;
Identifier _identifier;
public:
ScopedIdentifier() {}
inline std::vector<Identifier>& GetScope() noexcept { return _scope; }
inline const std::vector<Identifier>& GetScope() const noexcept { return _scope; }
inline Identifier& GetIdentifier() noexcept { return _identifier; }
inline const Identifier& GetIdentifier() const noexcept { return _identifier; }
};
}
#endif // MALACHSCRIPT_IDENTIFIER_HPP

View File

@ -20,6 +20,8 @@ namespace MalachScript {
static constinit Identifier _doubleName = u8"double";
static constinit Identifier _boolName = u8"bool";
static constinit Identifier _autoName = u8"auto";
class PrimitiveTypes {
public:
constexpr static const Identifier& VoidName() noexcept { return _voidName; }
@ -36,6 +38,7 @@ namespace MalachScript {
constexpr static const Identifier& FloatName() noexcept { return _floatName; }
constexpr static const Identifier& DoubleName() noexcept { return _doubleName; }
constexpr static const Identifier& BoolName() noexcept { return _boolName; }
constexpr static const Identifier& AutoName() noexcept { return _autoName; }
};
}

15
src/CoreData/TypeMod.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef MALACHSCRIPT_TYPEMOD_HPP
#define MALACHSCRIPT_TYPEMOD_HPP
#include <cstdint>
namespace MalachScript{
enum class TypeMod : uint8_t {
None = 0,
RefIn = 1,
RefOut = 2,
RefInOut = 3,
};
}
#endif // MALACHSCRIPT_TYPEMOD_HPP

View File

@ -0,0 +1,8 @@
#ifndef MALACHSCRIPT_PARSEDEXPRESSION_HPP
#define MALACHSCRIPT_PARSEDEXPRESSION_HPP
namespace MalachScript::Parser {
class ParsedExpression{};
}
#endif // MALACHSCRIPT_PARSEDEXPRESSION_HPP

View File

@ -1,5 +1,6 @@
#include "Parser.hpp"
#include <iostream>
#include "../CoreData/FuncAttr.hpp"
#include "../CoreData/PrimitiveTypes.hpp"
#define PROGRESS_TOKEN(token) \
@ -28,9 +29,10 @@ namespace MalachScript::Parser {
break;
}
const ParsedStatement* statement;
auto result = ParseClass(statement) || ParseNamespace(statement);
auto result = ParseClass(statement) || ParseFunc(statement) || ParseNamespace(statement);
if (!result) {
// TODO: Log error
PROGRESS_TOKEN(_currentToken);
continue;
}
statements.push_back(statement);
@ -61,7 +63,9 @@ namespace MalachScript::Parser {
}
// After class keyword, an identifier should always follow, if it doesn't, log an error.
Identifier identifier;
ParseIdentifier(identifier, current, encounteredError);
if (!ParseIdentifier(identifier, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
PROGRESS_TOKEN(current);
std::vector<Identifier> inherits;
std::vector<const ParsedStatement*> body;
@ -75,11 +79,15 @@ namespace MalachScript::Parser {
case LexTokenKind::ColonSymbol: {
PROGRESS_TOKEN(current);
Identifier id;
ParseIdentifier(id, current, encounteredError);
if (!ParseIdentifier(id, _currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
inherits.push_back(id);
while (current->GetKind() == LexTokenKind::CommaSymbol) {
PROGRESS_TOKEN(current);
ParseIdentifier(id, current, encounteredError);
if (!ParseIdentifier(id, _currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
inherits.push_back(id);
PROGRESS_TOKEN(current);
}
@ -121,14 +129,15 @@ namespace MalachScript::Parser {
auto start = _currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(_currentToken);
Identifier defineFrom;
auto encounteredErrors = false;
if (!ParsePrimType(defineFrom) && !ParseIdentifier(defineFrom, _currentToken, encounteredErrors)) {
if (!ParsePrimType(defineFrom, _currentToken) && !ParseIdentifier(defineFrom, _currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
PROGRESS_TOKEN(_currentToken);
Identifier defineTo;
ParseIdentifier(defineTo, _currentToken, encounteredErrors);
if (!ParseIdentifier(defineTo, _currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
PROGRESS_TOKEN(_currentToken);
EXPECT_TOKEN(_currentToken, SemicolonSymbol);
PROGRESS_TOKEN(_currentToken);
@ -142,21 +151,239 @@ namespace MalachScript::Parser {
auto start = _currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(_currentToken);
Identifier identifier;
bool encounteredErrors = false;
ParseIdentifier(identifier, _currentToken, encounteredErrors);
if (!ParseIdentifier(identifier, _currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, _currentToken->GetSpan());
}
auto script = ParseScript();
auto end = _currentToken->GetSpan().GetEnd();
PROGRESS_TOKEN(_currentToken);
out = new ParsedNamespaceStatement(TextSpan(start, end), identifier, script);
return true;
}
bool Parser::ParseFunc(const ParsedStatement*& out) {
auto start = _currentToken->GetSpan().GetStart();
const auto* token = _currentToken;
bool isShared = false;
bool isExternal = false;
bool modifiers = true;
while (modifiers) {
switch (token->GetKind()) {
case LexTokenKind::SharedKeyword:
isShared = true;
PROGRESS_TOKEN(token);
continue;
case LexTokenKind::ExternalKeyword:
isExternal = true;
PROGRESS_TOKEN(token);
continue;
default: modifiers = false; break;
}
}
AccessModifier accessModifier = AccessModifier::Public;
if (token->GetKind() == LexTokenKind::PrivateKeyword) {
accessModifier = AccessModifier::Private;
PROGRESS_TOKEN(token);
} else if (token->GetKind() == LexTokenKind::ProtectedKeyword) {
accessModifier = AccessModifier::Protected;
PROGRESS_TOKEN(token);
}
const ParsedStatement* typeStatement = nullptr;
bool returnsReference = false;
if (token->GetKind() == LexTokenKind::TildeSymbol) {
// TODO: Handle destructor
throw std::logic_error("not implemented");
} else if (ParseType(typeStatement, token)) {
if (token->GetKind() == LexTokenKind::AmpersandSymbol) {
returnsReference = true;
PROGRESS_TOKEN(token);
}
}
Identifier identifier;
if (!ParseIdentifier(identifier, token)) {
return false;
}
PROGRESS_TOKEN(token);
const ParsedStatement* paramList = nullptr;
if (!ParseParamList(paramList, token)) {
return false;
}
_currentToken = token;
bool isConst = false;
if (_currentToken->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(_currentToken);
}
bool lookingForFuncAttr = true;
FuncAttr funcAttr;
while (lookingForFuncAttr) {
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;
if (_currentToken->GetKind() != LexTokenKind::SemicolonSymbol) {
// TODO: Parse stat block.
throw std::logic_error("not implemented");
}
out = new ParsedFuncStatement(TextSpan(start, _currentToken->GetSpan().GetEnd()), isShared, isExternal,
accessModifier, typeStatement, returnsReference, identifier, paramList, isConst,
funcAttr, statblock);
return true;
}
bool Parser::ParseType(const ParsedStatement*& out, const LexToken*& currentToken) {
const auto* token = currentToken;
auto start = token->GetSpan().GetStart();
bool isConst = false;
bool isArray = false;
bool isHandle = false;
if (token->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(token);
}
ScopedIdentifier scopedIdentifier;
ParseScope(scopedIdentifier.GetScope(), token);
if (!ParseDataType(scopedIdentifier.GetIdentifier(), token)) {
return false;
}
// TODO: Generics.
if (token->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) {
PROGRESS_TOKEN(token);
if (token->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan());
} else {
PROGRESS_TOKEN(token);
isArray = true;
}
} else if (token->GetKind() == LexTokenKind::AtSymbol) {
isHandle = true;
PROGRESS_TOKEN(token);
if (token->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(token);
}
}
auto end = token->GetSpan().GetEnd();
currentToken = token;
out = new ParsedTypeStatement(TextSpan(start, end), isConst, isArray, isHandle, scopedIdentifier);
return true;
}
bool Parser::ParseScope(std::vector<Identifier>& scope, const LexToken*& currentToken) {
if (currentToken->GetKind() == LexTokenKind::ColonColonSymbol) {
scope.emplace_back();
PROGRESS_TOKEN(currentToken);
}
Identifier identifier;
if (ParseIdentifier(identifier, currentToken)) {
const auto* n = currentToken->GetNext().get();
currentToken = n;
scope.push_back(identifier);
} else {
return false;
}
while (currentToken != nullptr && currentToken->GetKind() == LexTokenKind::ColonColonSymbol) {
const auto* n = currentToken;
PROGRESS_TOKEN(n);
if (ParseIdentifier(identifier, n)) {
PROGRESS_TOKEN(n);
if (n->GetKind() == LexTokenKind::ColonColonSymbol) {
currentToken = n;
scope.push_back(identifier);
} else {
break;
}
} else {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
break;
}
}
// TODO: Handle generics in script class name.
return true;
}
bool Parser::ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) {
return false;
}
auto start = currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(currentToken);
std::vector<ParsedParamListStatement::ParsedParameter> parameters;
if (currentToken->GetKind() == LexTokenKind::VoidKeyword) {
PROGRESS_TOKEN(currentToken);
if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
}
PROGRESS_TOKEN(currentToken);
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
return true;
} else if (currentToken->GetKind() == LexTokenKind::CloseParenthesisSymbol) {
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
PROGRESS_TOKEN(currentToken);
return true;
}
while (true) {
parameters.emplace_back();
auto parameter = parameters.at(parameters.size() - 1);
if (!ParseType((const ParsedStatement*&)parameter.GetTypeStatement(), currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
}
ParseTypeMod(parameter.GetTypeMod());
ParseIdentifier(parameter.GetIdentifier(), currentToken);
if (currentToken->GetKind() != LexTokenKind::CommaSymbol) {
break;
}
PROGRESS_TOKEN(currentToken);
}
if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
}
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
PROGRESS_TOKEN(currentToken);
return true;
}
bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken) {
switch (currentToken->GetKind()) {
case LexTokenKind::Identifier:
out = static_cast<const IdentifierToken*>(currentToken)->GetValue();
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::AutoKeyword:
out = PrimitiveTypes::AutoName();
PROGRESS_TOKEN(currentToken);
return true;
default:
if (ParsePrimType(out, currentToken)) {
PROGRESS_TOKEN(currentToken);
return true;
}
return false;
}
}
bool Parser::ParseVirtProp([[maybe_unused]] const ParsedStatement*& out) { return false; }
bool Parser::ParseFunc([[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::ParsePrimType(Identifier& out) {
// TODO: out needs to return a value.
switch (_currentToken->GetKind()) {
bool Parser::ParsePrimType(Identifier& out, const LexToken*& token) {
switch (token->GetKind()) {
case LexTokenKind::VoidKeyword: out = PrimitiveTypes::VoidName(); return true;
case LexTokenKind::IntKeyword: out = PrimitiveTypes::IntName(); return true;
case LexTokenKind::Int8Keyword: out = PrimitiveTypes::Int8Name(); return true;
@ -174,4 +401,25 @@ namespace MalachScript::Parser {
default: return false;
}
}
bool Parser::ParseTypeMod(TypeMod& typeMod) {
if (_currentToken->GetKind() != LexTokenKind::AmpersandSymbol) {
return false;
}
PROGRESS_TOKEN(_currentToken);
switch (_currentToken->GetKind()) {
case LexTokenKind::InKeyword:
typeMod = TypeMod::RefIn;
PROGRESS_TOKEN(_currentToken);
return true;
case LexTokenKind::OutKeyword:
typeMod = TypeMod::RefOut;
PROGRESS_TOKEN(_currentToken);
return true;
case LexTokenKind::InoutKeyword:
typeMod = TypeMod::RefInOut;
PROGRESS_TOKEN(_currentToken);
return true;
default: typeMod = TypeMod::RefInOut; return true;
}
}
}

View File

@ -24,16 +24,21 @@ namespace MalachScript::Parser {
bool ParseClass(const ParsedStatement*& out);
bool ParseTypeDef(const ParsedStatement*& out);
bool ParseNamespace(const ParsedStatement*& out);
bool ParseVirtProp(const ParsedStatement*& out);
bool ParseFunc(const ParsedStatement*& out);
bool ParseType(const ParsedStatement*& out, const LexToken*& currentToken);
bool ParseScope(std::vector<Identifier>& out, const LexToken*& currentToken);
bool ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken);
bool ParseTypeMod(TypeMod& typeMod);
bool ParseDataType(Identifier& out, const LexToken*& currentToken);
bool ParseVirtProp(const ParsedStatement*& out);
bool ParseVar(const ParsedStatement*& out);
bool ParseFuncDef(const ParsedStatement*& out);
bool ParsePrimType(Identifier& out);
bool ParseIdentifier(Identifier& out, const LexToken* token, bool& logError) {
if (logError && token->GetKind() != LexTokenKind::Identifier) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan());
logError = false;
bool ParsePrimType(Identifier& out, const LexToken*& currentToken);
static bool ParseIdentifier(Identifier& out, const LexToken* token) {
if (token->GetKind() != LexTokenKind::Identifier) {
return false;
}
out = reinterpret_cast<const IdentifierToken*>(token)->GetValue();

View File

@ -1,8 +1,13 @@
#ifndef MALACHSCRIPT_PARSEDSTATEMENT_HPP
#define MALACHSCRIPT_PARSEDSTATEMENT_HPP
#include <utility>
#include <vector>
#include "../../CoreData/AccessModifier.hpp"
#include "../../CoreData/FuncAttr.hpp"
#include "../../CoreData/TypeMod.hpp"
#include "../../TextSpan.hpp"
#include "../Expressions/ParsedExpression.hpp"
#include "ParsedStatementKind.hpp"
namespace MalachScript::Parser {
class ParsedStatement {
@ -65,7 +70,7 @@ namespace MalachScript::Parser {
class ParsedNamespaceStatement : public ParsedStatementImpl<ParsedStatementKind::Namespace> {
Identifier _identifier;
const ParsedScriptStatement* _parsedScript;
std::unique_ptr<const ParsedStatement> _parsedScript;
public:
ParsedNamespaceStatement(TextSpan span, const Identifier& identifier, const ParsedScriptStatement* script)
@ -73,7 +78,100 @@ namespace MalachScript::Parser {
_parsedScript(script) {}
[[nodiscard]] inline const Identifier& GetIdentifier() const noexcept { return _identifier; }
[[nodiscard]] inline const ParsedScriptStatement* GetScript() const noexcept { return _parsedScript; }
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetScript() const noexcept {
return _parsedScript;
}
};
class ParsedTypeStatement : public ParsedStatementImpl<ParsedStatementKind::Type> {
bool _isConst;
bool _isArray;
bool _isHandle;
ScopedIdentifier _scopedIdentifier;
public:
ParsedTypeStatement(TextSpan span, bool isConst, bool isArray, bool isHandle,
const ScopedIdentifier& scopedIdentifier)
: ParsedStatementImpl<ParsedStatementKind::Type>(span), _isConst(isConst), _isArray(isArray),
_isHandle(isHandle), _scopedIdentifier(scopedIdentifier) {}
[[nodiscard]] inline bool IsConst() const noexcept { return _isConst; }
[[nodiscard]] inline bool IsArray() const noexcept { return _isArray; }
[[nodiscard]] inline bool IsHandle() const noexcept { return _isHandle; }
[[nodiscard]] inline const ScopedIdentifier& GetScopedIdentifier() const noexcept { return _scopedIdentifier; }
};
class ParsedParamListStatement : public ParsedStatementImpl<ParsedStatementKind::ParamList> {
public:
class ParsedParameter {
private:
const ParsedTypeStatement* _typeStatement = nullptr;
TypeMod _typeMod;
Identifier _identifier;
const ParsedExpression* _defaultExpression = nullptr;
public:
ParsedParameter(){};
[[nodiscard]] const ParsedTypeStatement*& GetTypeStatement() noexcept { return _typeStatement; }
[[nodiscard]] const ParsedTypeStatement* GetTypeStatement() const noexcept { return _typeStatement; }
[[nodiscard]] TypeMod& GetTypeMod() noexcept { return _typeMod; }
[[nodiscard]] const TypeMod& GetTypeMod() const noexcept { return _typeMod; }
[[nodiscard]] Identifier& GetIdentifier() noexcept { return _identifier; }
[[nodiscard]] const Identifier& GetIdentifier() const noexcept { return _identifier; }
[[nodiscard]] const ParsedExpression*& GetDefaultExpression() noexcept { return _defaultExpression; }
[[nodiscard]] const ParsedExpression* GetDefaultExpression() const noexcept { return _defaultExpression; }
};
private:
std::vector<ParsedParameter> _parameters;
public:
ParsedParamListStatement(TextSpan span, std::vector<ParsedParameter> parameters)
: ParsedStatementImpl<ParsedStatementKind::ParamList>(span), _parameters(std::move(parameters)){};
};
class ParsedFuncStatement : public ParsedStatementImpl<ParsedStatementKind::Func> {
private:
bool _isShared;
bool _isExternal;
AccessModifier _access;
std::unique_ptr<const ParsedStatement> _type;
bool _returnsReference;
Identifier _identifier;
std::unique_ptr<const ParsedStatement> _paramList;
bool isConst;
FuncAttr _funcAttr;
std::unique_ptr<const ParsedStatement> _statBlock;
public:
ParsedFuncStatement(const TextSpan& span, bool isShared, bool isExternal, AccessModifier access,
const ParsedStatement* type, bool returnsReference, const Identifier& identifier,
const ParsedStatement* paramList, bool isConst, FuncAttr funcAttr,
const ParsedStatement* statBlock)
: ParsedStatementImpl<ParsedStatementKind::Func>(span), _isShared(isShared), _isExternal(isExternal),
_access(access), _type(type), _returnsReference(returnsReference), _identifier(identifier),
_paramList(paramList), isConst(isConst), _funcAttr(funcAttr), _statBlock(statBlock) {}
[[nodiscard]] inline bool IsShared() const noexcept { return _isShared; }
[[nodiscard]] inline bool IsExternal() const noexcept { return _isExternal; }
[[nodiscard]] inline AccessModifier GetAccess() const noexcept { return _access; }
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetTypeStatement() const noexcept {
return _type;
}
[[nodiscard]] inline bool ReturnsReference() const noexcept { return _returnsReference; }
[[nodiscard]] inline const Identifier& GetIdentifier() const noexcept { return _identifier; }
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetParamList() const noexcept {
return _paramList;
}
[[nodiscard]] inline bool IsConst() const noexcept { return isConst; }
[[nodiscard]] inline FuncAttr GetFuncAttr() const noexcept { return _funcAttr; }
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetStatBlock() const noexcept {
return _statBlock;
}
};
}

View File

@ -7,7 +7,10 @@ namespace MalachScript::Parser {
Script,
Class,
TypeDef,
Namespace
Namespace,
Type,
ParamList,
Func,
};
}

View File

@ -3,28 +3,6 @@
using namespace MalachScript;
TEST_CASE("Parse basic class without body") {
std::vector<Parser::LexToken*> vec = {
new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::EndOfFile>(TextSpan(0, 0)),
};
for (size_t i = 0; i < vec.size() - 1; i++) {
vec[i]->SetNext(vec[i + 1]);
}
Diagnostics::Diagnostics diags;
auto parser = Parser::Parser(u8"class without body", vec.front(), &diags);
auto* script = parser.Parse();
REQUIRE(diags.GetMessages().empty());
{
REQUIRE(script->GetStatements().size() == 1);
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Class);
}
delete vec[0];
delete script;
}
#define PARSER_TEST(name, tokens, asserts) \
TEST_CASE(name) { \
std::vector<Parser::LexToken*> vec = { \

View File

@ -0,0 +1,52 @@
#include "../../extern/doctest.hpp"
#include "../../src/Parser/Parser.hpp"
using namespace MalachScript;
#define PARSER_TEST(name, tokens, asserts) \
TEST_CASE(name) { \
std::vector<Parser::LexToken*> vec = { \
tokens, \
new Parser::LexTokenImpl<Parser::LexTokenKind::EndOfFile>(TextSpan(0, 0)), \
}; \
for (size_t i = 0; i < vec.size() - 1; i++) { \
vec[i]->SetNext(vec[i + 1]); \
} \
Diagnostics::Diagnostics diags; \
auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags); \
auto* script = parser.Parse(); \
REQUIRE(diags.GetMessages().empty()); \
asserts; \
delete vec[0]; \
delete script; \
}
#define PARSER_TEST_TOKENS(...) __VA_ARGS__
PARSER_TEST("Parse ``void foobar();``",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::VoidKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
{
REQUIRE(script->GetStatements().size() == 1);
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
})
PARSER_TEST("Parse ``foo::bar::baz foobar();``",
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
{
REQUIRE(script->GetStatements().size() == 1);
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
})