Initial work on type registration in the binder.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2021-01-08 16:14:02 +01:00
parent da82819fff
commit 093ffde6bc
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
36 changed files with 819 additions and 386 deletions

View File

@ -19,7 +19,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_link_options(-fuse-ld=lld) add_link_options(-fuse-ld=lld)
endif () endif ()
file(GLOB_RECURSE SRC_FILES "src/*.cpp" "src/*.hpp") file(GLOB_RECURSE SRC_FILES "src/*.cpp")
add_library(MalachScript SHARED ${SRC_FILES}) add_library(MalachScript SHARED ${SRC_FILES})
set(LINKS) set(LINKS)

View File

@ -9,14 +9,14 @@ namespace MalachScriptRepl {
private: private:
WINDOW* _window; WINDOW* _window;
std::vector<std::u8string> _lines = {u8""}; std::vector<std::string> _lines = {""};
int _row = 0; int _row = 0;
int _col = 0; int _col = 0;
int _rightPos = 0; int _rightPos = 0;
int _scroll = 0; int _scroll = 0;
int _lineCount; int _lineCount;
std::function<void(const std::vector<std::u8string>&)> _onChange; std::function<void(const std::vector<std::string>&)> _onChange;
const MalachScript::Diagnostics::Diagnostic* _diag; const MalachScript::Diagnostics::Diagnostic* _diag;
public: public:
@ -26,7 +26,7 @@ namespace MalachScriptRepl {
_lineCount = height; _lineCount = height;
} }
inline void RegisterOnChange(std::function<void(const std::vector<std::u8string>&)> listener) { inline void RegisterOnChange(std::function<void(const std::vector<std::string>&)> listener) {
_onChange = listener; _onChange = listener;
} }
@ -99,7 +99,7 @@ namespace MalachScriptRepl {
} }
inline void Return() { inline void Return() {
_lines.insert(_lines.begin() + _row + _scroll + 1, u8""); _lines.insert(_lines.begin() + _row + _scroll + 1, "");
if (_row >= _lineCount - 1) { if (_row >= _lineCount - 1) {
ScrollDown(); ScrollDown();
} else { } else {
@ -119,10 +119,10 @@ namespace MalachScriptRepl {
wclrtoeol(_window); wclrtoeol(_window);
auto& line = _lines[_row + _scroll]; auto& line = _lines[_row + _scroll];
if ((int)line.length() <= _col) { if ((int)line.length() <= _col) {
line += u8" "; line += " ";
} else { } else {
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
line.insert(line.begin() + _col, u8' '); line.insert(line.begin() + _col, ' ');
} }
} }
waddstr(_window, (char*)line.c_str()); waddstr(_window, (char*)line.c_str());
@ -148,7 +148,7 @@ namespace MalachScriptRepl {
wmove(_window, _row, 0); wmove(_window, _row, 0);
auto& line = _lines[_row + _scroll]; auto& line = _lines[_row + _scroll];
if ((int)line.length() <= _col) { if ((int)line.length() <= _col) {
line += (char8_t)c; line += (char)c;
} else { } else {
line.insert(line.begin() + _col, c); line.insert(line.begin() + _col, c);
} }
@ -160,7 +160,7 @@ namespace MalachScriptRepl {
} }
inline void ResetText() { inline void ResetText() {
std::u8string script; std::string script;
for (size_t i = 0; i < _lines.size(); i++) { for (size_t i = 0; i < _lines.size(); i++) {
script += _lines[i]; script += _lines[i];
if (i != _lines.size() - 1) { if (i != _lines.size() - 1) {
@ -196,11 +196,11 @@ namespace MalachScriptRepl {
wmove(_window, _row, _col); wmove(_window, _row, _col);
} }
inline void SetScriptWithDiagnostics(std::u8string& script, const MalachScript::Diagnostics::Diagnostic* diag) { inline void SetScriptWithDiagnostics(std::string& script, const MalachScript::Diagnostics::Diagnostic* diag) {
_diag = diag; _diag = diag;
auto yx = GetCursorPosition(); auto yx = GetCursorPosition();
Clear(); Clear();
script += u8" "; script += " ";
size_t linenum = 0; size_t linenum = 0;
size_t index = 0; size_t index = 0;

View File

@ -7,9 +7,9 @@
#include "../src/Parser/Statements/ParsedStatementStringifier.hpp" #include "../src/Parser/Statements/ParsedStatementStringifier.hpp"
#include "InputWindow.hpp" #include "InputWindow.hpp"
void ParseAndUpdate(const std::vector<std::u8string>& lines, WINDOW* diagnosticsWindow, WINDOW* parsedWindow, void ParseAndUpdate(const std::vector<std::string>& lines, WINDOW* diagnosticsWindow, WINDOW* parsedWindow,
MalachScriptRepl::InputWindow& inputWindow) { MalachScriptRepl::InputWindow& inputWindow) {
std::u8string script; std::string script;
for (size_t i = 0; i < lines.size(); i++) { for (size_t i = 0; i < lines.size(); i++) {
script += lines[i]; script += lines[i];
if (i != lines.size() - 1) { if (i != lines.size() - 1) {
@ -23,9 +23,9 @@ void ParseAndUpdate(const std::vector<std::u8string>& lines, WINDOW* diagnostics
outfile.close(); outfile.close();
auto logger = MalachScript::Diagnostics::Logger(); auto logger = MalachScript::Diagnostics::Logger();
auto lexer = MalachScript::Parser::Lexer(u8"diag", script, &logger); auto lexer = MalachScript::Parser::Lexer("diag", script, &logger);
const auto* firstToken = lexer.Lex(); const auto* firstToken = lexer.Lex();
const auto* parsedResult = MalachScript::Parser::Parser::Parse(firstToken, u8"diag", &logger); const auto* parsedResult = MalachScript::Parser::Parser::Parse(firstToken, "diag", &logger);
const MalachScript::Diagnostics::Diagnostic* diag = nullptr; const MalachScript::Diagnostics::Diagnostic* diag = nullptr;
wclear(diagnosticsWindow); wclear(diagnosticsWindow);
@ -96,7 +96,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) {
auto inputWindow = MalachScriptRepl::InputWindow(inputFieldSize, maxX - 3, 1, 2); auto inputWindow = MalachScriptRepl::InputWindow(inputFieldSize, maxX - 3, 1, 2);
inputWindow.RegisterOnChange( inputWindow.RegisterOnChange(
[diagnosticsWindow, parsedResultWindow, &inputWindow](const std::vector<std::u8string>& lines) { [diagnosticsWindow, parsedResultWindow, &inputWindow](const std::vector<std::string>& lines) {
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow); ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow);
}); });

203
src/Binder/Binder.cpp Normal file
View File

@ -0,0 +1,203 @@
#include "Binder.hpp"
#include "../CoreData/PrimitiveTypes.hpp"
#include "../Diagnostics/Logger.hpp"
using namespace MalachScript::Parser;
using namespace MalachScript::Diagnostics;
namespace MalachScript::Binder {
void Binder::Bind(BoundNamespace* ns, const std::vector<const MalachScript::Parser::ParsedStatement*>& statements,
const Binder::log_func& log) {
for (const auto* s : statements) {
TypeRegistrationFirstPass(ns, s, {}, log);
}
for (const auto* s : statements) {
TypeRegistrationSecondPass(ns, s, {}, log);
}
for (const auto* s : statements) {
TypeRegistrationThirdPass(ns, s, {}, log);
}
FinaliseTypes(ns, log);
}
inline static std::optional<const BoundType*> ResolveType(BoundNamespace* ns, const Identifier& identifier) {
switch (identifier) {
case "int"_id: return MalachScript::PrimitiveTypes::IntType();
case "int8"_id: return MalachScript::PrimitiveTypes::Int8Type();
case "int16"_id: return MalachScript::PrimitiveTypes::Int16Type();
case "int32"_id: return MalachScript::PrimitiveTypes::Int32Type();
case "int64"_id: return MalachScript::PrimitiveTypes::Int64Type();
case "uint"_id: return MalachScript::PrimitiveTypes::UintType();
case "uint8"_id: return MalachScript::PrimitiveTypes::Uint8Type();
case "uint16"_id: return MalachScript::PrimitiveTypes::Uint16Type();
case "uint32"_id: return MalachScript::PrimitiveTypes::Uint32Type();
case "uint64"_id: return MalachScript::PrimitiveTypes::Uint64Type();
case "float"_id: return MalachScript::PrimitiveTypes::FloatType();
case "double"_id: return MalachScript::PrimitiveTypes::DoubleType();
case "bool"_id: return MalachScript::PrimitiveTypes::BoolType();
}
return ns->ResolveType(identifier);
}
void Binder::TypeRegistrationFirstPass(BoundNamespace* ns, const ParsedStatement* statement,
std::optional<BoundType*> activeType, const log_func& log) {
switch (statement->GetKind()) {
case Parser::ParsedStatementKind::Script: {
const auto* s = static_cast<const ParsedScriptStatement*>(statement);
for (const auto& child : s->GetStatements()) {
TypeRegistrationFirstPass(ns, child.get(), activeType, log);
}
break;
}
case Parser::ParsedStatementKind::Class: {
const auto* s = static_cast<const ParsedClassStatement*>(statement);
auto identifier = s->GetIdentifier();
if (activeType.has_value()) {
}
auto* type = new BoundType(s->GetClassAttr());
if (activeType.has_value()) {
activeType.value()->RegisterType(identifier, type);
} else {
ns->RegisterType(identifier, type);
}
for (const auto& child : s->GetBody()) {
TypeRegistrationFirstPass(ns, child.get(), type, log);
}
break;
}
case Parser::ParsedStatementKind::Namespace: {
const auto* s = static_cast<const ParsedNamespaceStatement*>(statement);
auto identifier = s->GetIdentifier();
auto* innerNamespace = new BoundNamespace();
ns->RegisterNamespace(identifier, innerNamespace);
TypeRegistrationFirstPass(innerNamespace, s->GetScript().get(), activeType, log);
break;
}
default: break;
}
}
void Binder::TypeRegistrationSecondPass(BoundNamespace* ns, const ParsedStatement* statement,
std::optional<BoundType*> activeType, const log_func& log) {
switch (statement->GetKind()) {
case ParsedStatementKind::Script: {
const auto* s = static_cast<const ParsedScriptStatement*>(statement);
for (const auto& child : s->GetStatements()) {
TypeRegistrationSecondPass(ns, child.get(), activeType, log);
}
break;
};
case ParsedStatementKind::Class: {
const auto* s = static_cast<const ParsedClassStatement*>(statement);
auto type = ns->ResolveType(s->GetIdentifier());
if (!type.has_value()) {
throw std::logic_error("Shouldn't be reached");
}
for (const auto& inherits : s->GetInherits()) {
auto inheritType = ResolveType(ns, inherits);
if (!inheritType.has_value()) {
log(DiagnosticLevel::Error, DiagnosticType::UnknownType, s->GetSpan(),
{inherits.GetStdString()});
} else {
type.value()->AddInheritType(inheritType.value());
}
}
for (const auto& child : s->GetBody()) {
TypeRegistrationSecondPass(ns, child.get(), type.value(), log);
}
break;
}
case ParsedStatementKind::TypeDef: {
const auto* s = static_cast<const ParsedTypeDefStatement*>(statement);
auto defineTo = s->GetDefineTo();
auto defineFrom = s->GetDefineFrom();
auto defineFromType = ResolveType(ns, defineFrom);
if (!defineFromType.has_value()) {
log(DiagnosticLevel::Error, DiagnosticType::UnknownType, s->GetSpan(), {defineFrom.GetStdString()});
} else {
if (activeType.has_value()) {
activeType.value()->RegisterType(defineTo, defineFromType.value());
} else {
ns->RegisterType(defineTo, defineFromType.value());
}
}
break;
}
case ParsedStatementKind::Namespace: {
const auto* s = static_cast<const ParsedNamespaceStatement*>(statement);
auto identifier = s->GetIdentifier();
auto innerNamespace = ns->ResolveNamespace(identifier);
if (!innerNamespace.has_value()) {
throw std::logic_error("Shouldn't be reached");
}
TypeRegistrationSecondPass(innerNamespace.value(), s->GetScript().get(), activeType, log);
break;
};
default: break;
}
}
void Binder::TypeRegistrationThirdPass(BoundNamespace* ns, const MalachScript::Parser::ParsedStatement* statement,
std::optional<BoundType*> activeType, const Binder::log_func& log) {
switch (statement->GetKind()) {
case ParsedStatementKind::Script: {
const auto* s = static_cast<const ParsedScriptStatement*>(statement);
for (const auto& child : s->GetStatements()) {
TypeRegistrationThirdPass(ns, child.get(), activeType, log);
}
break;
};
case ParsedStatementKind::Class: {
const auto* s = static_cast<const ParsedClassStatement*>(statement);
auto type = ns->ResolveType(s->GetIdentifier());
if (!type.has_value()) {
throw std::logic_error("Shouldn't be reached");
}
for (const auto& child : s->GetBody()) {
TypeRegistrationThirdPass(ns, child.get(), type.value(), log);
}
break;
}
case ParsedStatementKind::Namespace: {
const auto* s = static_cast<const ParsedNamespaceStatement*>(statement);
auto identifier = s->GetIdentifier();
auto innerNamespace = ns->ResolveNamespace(identifier);
if (!innerNamespace.has_value()) {
throw std::logic_error("Shouldn't be reached");
}
TypeRegistrationThirdPass(innerNamespace.value(), s->GetScript().get(), activeType, log);
break;
};
case ParsedStatementKind::Var: {
const auto* var = static_cast<const ParsedVarStatement*>(statement);
const auto& typeStatement = var->GetTypeStatement();
// FIXME: Resolve namespace of scoped identifier
auto type = ResolveType(ns, typeStatement->GetScopedIdentifier().GetIdentifier());
if (!type.has_value()) {
throw std::logic_error("Shouldn't be reached");
}
if (activeType.has_value()) {
activeType.value()->AddField(var->GetIdentifier(),
new BoundVariable(type.value(), var->GetAccess()));
} else {
ns->AddVariable(var->GetIdentifier(), new BoundVariable(type.value(), var->GetAccess()));
}
break;
}
default: break;
}
}
static void FinaliseNamespace(BoundNamespace* ns, const Binder::log_func& log) {
for (const auto& t : ns->GetTypes()) {
t.second->Finalise();
}
for (const auto& n : ns->GetNamespaces()) {
FinaliseNamespace(n.second, log);
}
}
void Binder::FinaliseTypes(BoundNamespace* ns, const Binder::log_func& log) { FinaliseNamespace(ns, log); }
}

36
src/Binder/Binder.hpp Normal file
View File

@ -0,0 +1,36 @@
#ifndef MALACHSCRIPT_BINDER_HPP
#define MALACHSCRIPT_BINDER_HPP
#include <functional>
#include "../Diagnostics/Logger.hpp"
#include "../Parser/Statements/ParsedStatement.hpp"
#include "BoundNamespace.hpp"
namespace MalachScript::Binder {
class Binder {
public:
using log_func = const std::function<void(Diagnostics::DiagnosticLevel level, Diagnostics::DiagnosticType,
const TextSpan&, const std::vector<std::string>&)>;
static void Bind(BoundNamespace* ns,
const std::vector<const MalachScript::Parser::ParsedStatement*>& statements,
const log_func& log);
private:
// Register all types and namespaces
static void TypeRegistrationFirstPass(BoundNamespace* ns,
const MalachScript::Parser::ParsedStatement* statement,
std::optional<BoundType*> activeType, const log_func& log);
// Register typedefs and type inheritance
static void TypeRegistrationSecondPass(BoundNamespace* ns,
const MalachScript::Parser::ParsedStatement* statement,
std::optional<BoundType*> activeType, const log_func& log);
// Register variables, fields, etc
static void TypeRegistrationThirdPass(BoundNamespace* ns,
const MalachScript::Parser::ParsedStatement* statement,
std::optional<BoundType*> activeType, const log_func& log);
// Finalise types, calculating size.
static void FinaliseTypes(BoundNamespace* ns, const log_func& log);
};
}
#endif // MALACHSCRIPT_BINDER_HPP

View File

@ -0,0 +1,50 @@
#ifndef MALACHSCRIPT_BOUNDNAMESPACE_HPP
#define MALACHSCRIPT_BOUNDNAMESPACE_HPP
#include <optional>
#include <unordered_map>
#include "../CoreData/Identifier.hpp"
#include "BoundType.hpp"
#include "BoundVariable.hpp"
namespace MalachScript::Binder {
class BoundNamespace {
public:
inline void RegisterNamespace(const Identifier& identifier, BoundNamespace* ns) {
_namespaces[identifier] = ns;
}
inline void RegisterType(const Identifier& identifier, BoundType* type) { _types[identifier] = type; }
inline void RegisterType(const Identifier& identifier, const BoundType* type) {
_types[identifier] = const_cast<BoundType*>(type);
}
inline void AddVariable(const Identifier& identifier, BoundVariable* var) { _variables[identifier] = var; }
inline std::optional<BoundType*> ResolveType(const Identifier& identifier) const noexcept {
auto find = _types.find(identifier);
if (find == _types.end()) {
return {};
}
return find->second;
}
inline std::optional<BoundNamespace*> ResolveNamespace(const Identifier& identifier) const noexcept {
auto find = _namespaces.find(identifier);
if (find == _namespaces.end()) {
return {};
}
return find->second;
}
inline const std::unordered_map<Identifier, BoundNamespace*>& GetNamespaces() const noexcept {
return _namespaces;
}
inline const std::unordered_map<Identifier, BoundType*>& GetTypes() const noexcept { return _types; }
private:
std::unordered_map<Identifier, BoundNamespace*> _namespaces;
std::unordered_map<Identifier, BoundType*> _types;
std::unordered_map<Identifier, BoundVariable*> _variables;
};
}
#endif // MALACHSCRIPT_BOUNDNAMESPACE_HPP

43
src/Binder/BoundType.hpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef MALACHSCRIPT_BOUNDTYPE_HPP
#define MALACHSCRIPT_BOUNDTYPE_HPP
#include <unordered_map>
#include "BoundVariable.hpp"
namespace MalachScript::Binder {
class BoundType {
public:
BoundType(ClassAttr classAttr) : _classAttr(classAttr) {}
BoundType(ClassAttr classAttr, size_t size) : _classAttr(classAttr), _size(size), _inherits(0) {}
inline void Finalise() noexcept {
_initialised = true;
// TODO: Calculate size
}
[[nodiscard]] inline size_t GetSize() const noexcept { return _size; }
[[nodiscard]] inline ClassAttr GetAttributes() const noexcept { return _classAttr; }
inline void AddInheritType(const BoundType* type) { _inherits.push_back(type); }
inline void AddField(const Identifier& identifier, BoundVariable* var) {
_fields.push_back(var);
_fieldsLookup[identifier] = var;
}
inline void RegisterType(const Identifier& identifier, const BoundType* type) {
_types[identifier] = const_cast<BoundType*>(type);
}
private:
bool _initialised = false;
ClassAttr _classAttr;
size_t _size = 0;
std::vector<const BoundType*> _inherits;
std::vector<BoundVariable*> _fields;
std::unordered_map<Identifier, BoundVariable*> _fieldsLookup;
// TODO: functions
std::unordered_map<Identifier, BoundType*> _types;
};
}
#endif // MALACHSCRIPT_BOUNDTYPE_HPP

View File

@ -0,0 +1,21 @@
#ifndef MALACHSCRIPT_BOUNDVARIABLE_HPP
#define MALACHSCRIPT_BOUNDVARIABLE_HPP
namespace MalachScript::Binder {
class BoundType;
class BoundVariable {
public:
BoundVariable(const BoundType* type, AccessModifier accessModifier)
: _type(type), _accessModifier(accessModifier) {}
[[nodiscard]] inline const BoundType* GetType() const noexcept { return _type; }
[[nodiscard]] inline AccessModifier GetAccess() const noexcept { return _accessModifier; }
private:
const BoundType* _type;
AccessModifier _accessModifier;
};
}
#endif // MALACHSCRIPT_BOUNDVARIABLE_HPP

View File

@ -2,7 +2,10 @@
#define MALACHSCRIPT_IDENTIFIER_HPP #define MALACHSCRIPT_IDENTIFIER_HPP
#include <cstdint> #include <cstdint>
#include <string>
#include <string_view> #include <string_view>
#include <vector>
namespace MalachScript { namespace MalachScript {
constexpr static uint32_t crc_table[256] = { constexpr static uint32_t crc_table[256] = {
@ -35,28 +38,30 @@ namespace MalachScript {
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
static int constexpr CalcLength(const char8_t* str) { return *str ? 1 + CalcLength(str + 1) : 0; } static int constexpr CalcLength(const char* str) { return *str ? 1 + CalcLength(str + 1) : 0; }
static std::u8string empty; static std::string empty;
class Identifier { class Identifier {
const char8_t* _str; const char* _str;
size_t _length; size_t _length;
uint32_t _hash; uint32_t _hash;
public: public:
Identifier() : _str(nullptr), _length(0), _hash(0) {} Identifier() : _str(nullptr), _length(0), _hash(0) {}
constexpr Identifier(const char8_t* c) : _str(c), _length(CalcLength(c)), _hash(Hash(c)) {} constexpr Identifier(const char* c) : _str(c), _length(CalcLength(c)), _hash(Hash(c)) {}
constexpr Identifier(const char8_t* c, size_t length, uint32_t hash) : _str(c), _length(length), _hash(hash) {} constexpr Identifier(const char* c, size_t length) : _str(c), _length(length), _hash(Hash(c)) {}
constexpr Identifier(const char* c, size_t length, uint32_t hash) : _str(c), _length(length), _hash(hash) {}
[[nodiscard]] constexpr inline uint32_t GetHash() const noexcept { return _hash; } [[nodiscard]] constexpr inline uint32_t GetHash() const noexcept { return _hash; }
[[nodiscard]] constexpr inline std::u8string_view GetString() const noexcept { [[nodiscard]] constexpr inline std::string_view GetString() const noexcept {
return std::u8string_view(_str, _length); return std::string_view(_str, _length);
} }
[[nodiscard]] inline std::string GetStdString() const noexcept { return std::string((char*)_str, _length); }
[[nodiscard]] constexpr inline size_t GetLength() const noexcept { return _length; } [[nodiscard]] constexpr inline size_t GetLength() const noexcept { return _length; }
constexpr inline static uint32_t Hash(const std::u8string_view& sv) { constexpr inline static uint32_t Hash(const std::string_view& sv) {
uint32_t crc = 0xffffffff; uint32_t crc = 0xffffffff;
for (auto c : sv) { for (auto c : sv) {
crc = (crc >> 8) ^ crc_table[(crc ^ c) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ c) & 0xff];
@ -64,6 +69,9 @@ namespace MalachScript {
return crc ^ 0xffffffff; return crc ^ 0xffffffff;
} }
[[nodiscard]] inline constexpr std::size_t operator()() const noexcept { return _hash; }
[[nodiscard]] inline constexpr operator uint32_t() const noexcept { return _hash; }
friend std::ostream& operator<<(std::ostream& out, const Identifier& c) { friend std::ostream& operator<<(std::ostream& out, const Identifier& c) {
out << std::string((const char*)c._str, c._length); out << std::string((const char*)c._str, c._length);
return out; return out;
@ -86,4 +94,18 @@ namespace MalachScript {
}; };
} }
namespace std {
/// @brief Helper class for getting the hash of a string view literal.
template <> struct hash<MalachScript::Identifier> {
/// @brief Returns the hash of a stringview.
/// @param s a StringView.
/// @return The hash of the StringView.
constexpr std::size_t operator()(MalachScript::Identifier const& s) const noexcept { return s.GetHash(); }
};
}
inline constexpr MalachScript::Identifier operator"" _id(const char* c, size_t l) {
return MalachScript::Identifier(c, l);
}
#endif // MALACHSCRIPT_IDENTIFIER_HPP #endif // MALACHSCRIPT_IDENTIFIER_HPP

View File

@ -2,6 +2,7 @@
#define MALACHSCRIPT_PRIMITIVETYPES_HPP #define MALACHSCRIPT_PRIMITIVETYPES_HPP
#include <string> #include <string>
#include "../Binder/BoundType.hpp"
#include "Identifier.hpp" #include "Identifier.hpp"
#if !__cpp_constinit #if !__cpp_constinit
@ -9,22 +10,34 @@
#endif #endif
namespace MalachScript { namespace MalachScript {
static constinit Identifier _voidName = u8"void"; static constinit Identifier _voidName = "void";
static constinit Identifier _intName = u8"int"; static constinit Identifier _intName = "int";
static constinit Identifier _int8Name = u8"int8"; static constinit Identifier _int8Name = "int8";
static constinit Identifier _int16Name = u8"int16"; static constinit Identifier _int16Name = "int16";
static constinit Identifier _int32Name = u8"int32"; static constinit Identifier _int32Name = "int32";
static constinit Identifier _int64Name = u8"int64"; static constinit Identifier _int64Name = "int64";
static constinit Identifier _uintName = u8"uint"; static constinit Identifier _uintName = "uint";
static constinit Identifier _uint8Name = u8"uint8"; static constinit Identifier _uint8Name = "uint8";
static constinit Identifier _uint16Name = u8"uint16"; static constinit Identifier _uint16Name = "uint16";
static constinit Identifier _uint32Name = u8"uint32"; static constinit Identifier _uint32Name = "uint32";
static constinit Identifier _uint64Name = u8"uint64"; static constinit Identifier _uint64Name = "uint64";
static constinit Identifier _floatName = u8"float"; static constinit Identifier _floatName = "float";
static constinit Identifier _doubleName = u8"double"; static constinit Identifier _doubleName = "double";
static constinit Identifier _boolName = u8"bool"; static constinit Identifier _boolName = "bool";
static constinit Identifier _autoName = u8"auto"; static constinit Identifier _autoName = "auto";
static Binder::BoundType _int8Type = Binder::BoundType(ClassAttr::None, sizeof(int8_t));
static Binder::BoundType _int16Type = Binder::BoundType(ClassAttr::None, sizeof(int16_t));
static Binder::BoundType _int32Type = Binder::BoundType(ClassAttr::None, sizeof(int32_t));
static Binder::BoundType _int64Type = Binder::BoundType(ClassAttr::None, sizeof(int64_t));
static Binder::BoundType _uint8Type = Binder::BoundType(ClassAttr::None, sizeof(uint8_t));
static Binder::BoundType _uint16Type = Binder::BoundType(ClassAttr::None, sizeof(uint16_t));
static Binder::BoundType _uint32Type = Binder::BoundType(ClassAttr::None, sizeof(uint32_t));
static Binder::BoundType _uint64Type = Binder::BoundType(ClassAttr::None, sizeof(uint64_t));
static Binder::BoundType _floatType = Binder::BoundType(ClassAttr::None, sizeof(float));
static Binder::BoundType _doubleType = Binder::BoundType(ClassAttr::None, sizeof(double));
static Binder::BoundType _boolType = Binder::BoundType(ClassAttr::None, sizeof(uint8_t));
class PrimitiveTypes { class PrimitiveTypes {
public: public:
@ -43,6 +56,20 @@ namespace MalachScript {
constexpr static const Identifier& DoubleName() noexcept { return _doubleName; } constexpr static const Identifier& DoubleName() noexcept { return _doubleName; }
constexpr static const Identifier& BoolName() noexcept { return _boolName; } constexpr static const Identifier& BoolName() noexcept { return _boolName; }
constexpr static const Identifier& AutoName() noexcept { return _autoName; } constexpr static const Identifier& AutoName() noexcept { return _autoName; }
constexpr static const Binder::BoundType* IntType() noexcept { return &_int32Type; }
constexpr static const Binder::BoundType* Int8Type() noexcept { return &_int8Type; }
constexpr static const Binder::BoundType* Int16Type() noexcept { return &_int16Type; }
constexpr static const Binder::BoundType* Int32Type() noexcept { return &_int32Type; }
constexpr static const Binder::BoundType* Int64Type() noexcept { return &_int64Type; }
constexpr static const Binder::BoundType* UintType() noexcept { return &_uint32Type; }
constexpr static const Binder::BoundType* Uint8Type() noexcept { return &_uint8Type; }
constexpr static const Binder::BoundType* Uint16Type() noexcept { return &_uint16Type; }
constexpr static const Binder::BoundType* Uint32Type() noexcept { return &_uint32Type; }
constexpr static const Binder::BoundType* Uint64Type() noexcept { return &_uint64Type; }
constexpr static const Binder::BoundType* FloatType() noexcept { return &_floatType; }
constexpr static const Binder::BoundType* DoubleType() noexcept { return &_doubleType; }
constexpr static const Binder::BoundType* BoolType() noexcept { return &_boolType; }
}; };
} }

View File

@ -9,19 +9,19 @@ namespace MalachScript::Diagnostics {
class Diagnostic { class Diagnostic {
DiagnosticLevel _level; DiagnosticLevel _level;
DiagnosticType _type; DiagnosticType _type;
std::u8string_view _scriptName; std::string_view _scriptName;
TextSpan _span; TextSpan _span;
std::vector<std::string> _formats; std::vector<std::string> _formats;
public: public:
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::u8string_view& scriptName, inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::string_view& scriptName, TextSpan span,
TextSpan span, const std::vector<std::string>& formats = {}) const std::vector<std::string>& formats = {})
: _level(level), _type(type), _scriptName(scriptName), _span(span), _formats(formats) {} : _level(level), _type(type), _scriptName(scriptName), _span(span), _formats(formats) {}
[[nodiscard]] inline DiagnosticLevel GetLevel() const noexcept { return _level; } [[nodiscard]] inline DiagnosticLevel GetLevel() const noexcept { return _level; }
[[nodiscard]] inline DiagnosticType GetType() const noexcept { return _type; } [[nodiscard]] inline DiagnosticType GetType() const noexcept { return _type; }
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; } [[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
[[nodiscard]] inline const std::u8string_view& GetScriptName() const noexcept { return _scriptName; } [[nodiscard]] inline const std::string_view& GetScriptName() const noexcept { return _scriptName; }
[[nodiscard]] inline const std::vector<std::string>& GetFormats() const noexcept { return _formats; } [[nodiscard]] inline const std::vector<std::string>& GetFormats() const noexcept { return _formats; }
}; };
} }

View File

@ -8,6 +8,8 @@ namespace MalachScript::Diagnostics {
ExpectedEndOfString, ExpectedEndOfString,
UnexpectedToken, UnexpectedToken,
DoubleProperty, DoubleProperty,
UnknownType,
}; };
} }

View File

@ -23,6 +23,8 @@ namespace MalachScript::Diagnostics {
diag->GetFormats()); diag->GetFormats());
} }
case DiagnosticType::DoubleProperty: return "Property block found twice."; case DiagnosticType::DoubleProperty: return "Property block found twice.";
case DiagnosticType::UnknownType: util::Format("Unknown Type Encounted: '{0}'", diag->GetFormats());
} }
return std::to_string((uint8_t)diag->GetType()); return std::to_string((uint8_t)diag->GetType());
} }

View File

@ -9,24 +9,24 @@ namespace MalachScript::Diagnostics {
std::vector<Diagnostic> _messages; std::vector<Diagnostic> _messages;
public: public:
inline void Log(DiagnosticLevel level, DiagnosticType type, std::u8string_view scriptName, TextSpan span, inline void Log(DiagnosticLevel level, DiagnosticType type, std::string_view scriptName, TextSpan span,
const std::vector<std::string>& formats = {}) { const std::vector<std::string>& formats = {}) {
_messages.emplace_back(level, type, scriptName, span, formats); _messages.emplace_back(level, type, scriptName, span, formats);
} }
inline void LogTrace(DiagnosticType type, std::u8string_view scriptName, TextSpan span) { inline void LogTrace(DiagnosticType type, std::string_view scriptName, TextSpan span) {
Log(DiagnosticLevel::Trace, type, scriptName, span); Log(DiagnosticLevel::Trace, type, scriptName, span);
} }
inline void LogInfo(DiagnosticType type, std::u8string_view scriptName, TextSpan span) { inline void LogInfo(DiagnosticType type, std::string_view scriptName, TextSpan span) {
Log(DiagnosticLevel::Information, type, scriptName, span); Log(DiagnosticLevel::Information, type, scriptName, span);
} }
inline void LogWarning(DiagnosticType type, std::u8string_view scriptName, TextSpan span) { inline void LogWarning(DiagnosticType type, std::string_view scriptName, TextSpan span) {
Log(DiagnosticLevel::Warning, type, scriptName, span); Log(DiagnosticLevel::Warning, type, scriptName, span);
} }
inline void LogError(DiagnosticType type, std::u8string_view scriptName, TextSpan span, inline void LogError(DiagnosticType type, std::string_view scriptName, TextSpan span,
const std::vector<std::string>& formats = {}) { const std::vector<std::string>& formats = {}) {
Log(DiagnosticLevel::Error, type, scriptName, span, formats); Log(DiagnosticLevel::Error, type, scriptName, span, formats);
} }
inline void LogCritical(DiagnosticType type, std::u8string_view scriptName, TextSpan span) { inline void LogCritical(DiagnosticType type, std::string_view scriptName, TextSpan span) {
Log(DiagnosticLevel::Critical, type, scriptName, span); Log(DiagnosticLevel::Critical, type, scriptName, span);
} }

View File

@ -25,13 +25,13 @@ namespace MalachScript::Parser {
auto start = _position; auto start = _position;
auto c = Consume(); auto c = Consume();
switch (c) { switch (c) {
case u8'\0': return Create<LexTokenImpl<LexTokenKind::EndOfFile>>(TextSpan(start + 1, start + 2)); case '\0': return Create<LexTokenImpl<LexTokenKind::EndOfFile>>(TextSpan(start + 1, start + 2));
case u8'*': { case '*': {
auto n = Peek(); auto n = Peek();
if (n == u8'*') { if (n == '*') {
Progress(); Progress();
n = Peek(); n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// **= // **=
return Create<LexTokenImpl<LexTokenKind::StarStarEqualsSymbol>>(TextSpan(start, start + 3)); return Create<LexTokenImpl<LexTokenKind::StarStarEqualsSymbol>>(TextSpan(start, start + 3));
@ -39,7 +39,7 @@ namespace MalachScript::Parser {
// ** // **
return Create<LexTokenImpl<LexTokenKind::StarStarSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::StarStarSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// *= // *=
return Create<LexTokenImpl<LexTokenKind::StarEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::StarEqualsSymbol>>(TextSpan(start, start + 2));
@ -47,30 +47,30 @@ namespace MalachScript::Parser {
// * // *
return Create<LexTokenImpl<LexTokenKind::StarSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::StarSymbol>>(TextSpan(start, start + 1));
} }
case u8'/': case '/':
if (Peek() == u8'=') { if (Peek() == '=') {
Progress(); Progress();
// /= // /=
return Create<LexTokenImpl<LexTokenKind::SlashEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::SlashEqualsSymbol>>(TextSpan(start, start + 2));
} }
// / // /
return Create<LexTokenImpl<LexTokenKind::SlashSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::SlashSymbol>>(TextSpan(start, start + 1));
case u8'%': case '%':
if (Peek() == u8'=') { if (Peek() == '=') {
Progress(); Progress();
// %= // %=
return Create<LexTokenImpl<LexTokenKind::PercentEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::PercentEqualsSymbol>>(TextSpan(start, start + 2));
} }
// % // %
return Create<LexTokenImpl<LexTokenKind::PercentSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::PercentSymbol>>(TextSpan(start, start + 1));
case u8'+': { case '+': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// += // +=
return Create<LexTokenImpl<LexTokenKind::PlusEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::PlusEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'+') { if (n == '+') {
Progress(); Progress();
// ++ // ++
return Create<LexTokenImpl<LexTokenKind::PlusPlusSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::PlusPlusSymbol>>(TextSpan(start, start + 2));
@ -78,14 +78,14 @@ namespace MalachScript::Parser {
// + // +
return Create<LexTokenImpl<LexTokenKind::PlusSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::PlusSymbol>>(TextSpan(start, start + 1));
} }
case u8'-': { case '-': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// -= // -=
return Create<LexTokenImpl<LexTokenKind::MinusEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::MinusEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'-') { if (n == '-') {
Progress(); Progress();
// -- // --
return Create<LexTokenImpl<LexTokenKind::MinusMinusSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::MinusMinusSymbol>>(TextSpan(start, start + 2));
@ -93,16 +93,16 @@ namespace MalachScript::Parser {
// - // -
return Create<LexTokenImpl<LexTokenKind::MinusSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::MinusSymbol>>(TextSpan(start, start + 1));
} }
case u8'<': { case '<': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// <= // <=
return Create<LexTokenImpl<LexTokenKind::LessThanEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::LessThanEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'<') { if (n == '<') {
Progress(); Progress();
if (Peek() == u8'=') { if (Peek() == '=') {
Progress(); Progress();
// <<= // <<=
return Create<LexTokenImpl<LexTokenKind::LessThanLessThanEqualsSymbol>>( return Create<LexTokenImpl<LexTokenKind::LessThanLessThanEqualsSymbol>>(
@ -114,25 +114,25 @@ namespace MalachScript::Parser {
// < // <
return Create<LexTokenImpl<LexTokenKind::LessThanSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::LessThanSymbol>>(TextSpan(start, start + 1));
} }
case u8'>': { case '>': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// >= // >=
return Create<LexTokenImpl<LexTokenKind::GreaterThanEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::GreaterThanEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'>') { if (n == '>') {
Progress(); Progress();
n = Peek(); n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// >>= // >>=
return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanEqualsSymbol>>( return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanEqualsSymbol>>(
TextSpan(start, start + 3)); TextSpan(start, start + 3));
} }
if (n == u8'>') { if (n == '>') {
Progress(); Progress();
if (Peek() == u8'=') { if (Peek() == '=') {
Progress(); Progress();
// >>>= // >>>=
return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanGreaterThanEqualsSymbol>>( return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanGreaterThanEqualsSymbol>>(
@ -148,10 +148,10 @@ namespace MalachScript::Parser {
// > // >
return Create<LexTokenImpl<LexTokenKind::GreaterThanSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::GreaterThanSymbol>>(TextSpan(start, start + 1));
} }
case u8'(': return Create<LexTokenImpl<LexTokenKind::OpenParenthesisSymbol>>(TextSpan(start, start + 1)); case '(': return Create<LexTokenImpl<LexTokenKind::OpenParenthesisSymbol>>(TextSpan(start, start + 1));
case u8')': return Create<LexTokenImpl<LexTokenKind::CloseParenthesisSymbol>>(TextSpan(start, start + 1)); case ')': return Create<LexTokenImpl<LexTokenKind::CloseParenthesisSymbol>>(TextSpan(start, start + 1));
case u8'=': { case '=': {
if (Peek() == u8'=') { if (Peek() == '=') {
Progress(); Progress();
// == // ==
return Create<LexTokenImpl<LexTokenKind::EqualsEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::EqualsEqualsSymbol>>(TextSpan(start, start + 2));
@ -159,14 +159,14 @@ namespace MalachScript::Parser {
// = // =
return Create<LexTokenImpl<LexTokenKind::EqualsSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::EqualsSymbol>>(TextSpan(start, start + 1));
} }
case u8'!': { case '!': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// != // !=
return Create<LexTokenImpl<LexTokenKind::ExclamationMarkEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::ExclamationMarkEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'i' && Peek(2) == u8's') { if (n == 'i' && Peek(2) == 's') {
Progress(2); Progress(2);
// !is // !is
return Create<LexTokenImpl<LexTokenKind::ExclamationMarkIsSymbol>>(TextSpan(start, start + 3)); return Create<LexTokenImpl<LexTokenKind::ExclamationMarkIsSymbol>>(TextSpan(start, start + 3));
@ -174,9 +174,9 @@ namespace MalachScript::Parser {
// ! // !
return Create<LexTokenImpl<LexTokenKind::ExclamationMarkSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::ExclamationMarkSymbol>>(TextSpan(start, start + 1));
} }
case u8'?': return Create<LexTokenImpl<LexTokenKind::QuestionMarkSymbol>>(TextSpan(start, start + 1)); case '?': return Create<LexTokenImpl<LexTokenKind::QuestionMarkSymbol>>(TextSpan(start, start + 1));
case u8':': { case ':': {
if (Peek() == u8':') { if (Peek() == ':') {
Progress(); Progress();
// :: // ::
return Create<LexTokenImpl<LexTokenKind::ColonColonSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::ColonColonSymbol>>(TextSpan(start, start + 2));
@ -184,14 +184,14 @@ namespace MalachScript::Parser {
// : // :
return Create<LexTokenImpl<LexTokenKind::ColonSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::ColonSymbol>>(TextSpan(start, start + 1));
} }
case u8'&': { case '&': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// &= // &=
return Create<LexTokenImpl<LexTokenKind::AmpersandEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::AmpersandEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'&') { if (n == '&') {
Progress(); Progress();
// && // &&
return Create<LexTokenImpl<LexTokenKind::AmpersandAmpersandSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::AmpersandAmpersandSymbol>>(TextSpan(start, start + 2));
@ -199,20 +199,19 @@ namespace MalachScript::Parser {
// & // &
return Create<LexTokenImpl<LexTokenKind::AmpersandSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::AmpersandSymbol>>(TextSpan(start, start + 1));
} }
case u8',': return Create<LexTokenImpl<LexTokenKind::CommaSymbol>>(TextSpan(start, start + 1)); case ',': return Create<LexTokenImpl<LexTokenKind::CommaSymbol>>(TextSpan(start, start + 1));
case u8'{': case '{': return Create<LexTokenImpl<LexTokenKind::OpenCurlyParenthesisSymbol>>(TextSpan(start, start + 1));
return Create<LexTokenImpl<LexTokenKind::OpenCurlyParenthesisSymbol>>(TextSpan(start, start + 1)); case '}':
case u8'}':
return Create<LexTokenImpl<LexTokenKind::CloseCurlyParenthesisSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::CloseCurlyParenthesisSymbol>>(TextSpan(start, start + 1));
case u8';': return Create<LexTokenImpl<LexTokenKind::SemicolonSymbol>>(TextSpan(start, start + 1)); case ';': return Create<LexTokenImpl<LexTokenKind::SemicolonSymbol>>(TextSpan(start, start + 1));
case u8'|': { case '|': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// |= // |=
return Create<LexTokenImpl<LexTokenKind::VerticalLineEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::VerticalLineEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'|') { if (n == '|') {
Progress(); Progress();
// || // ||
return Create<LexTokenImpl<LexTokenKind::VerticalLineVerticalLineSymbol>>( return Create<LexTokenImpl<LexTokenKind::VerticalLineVerticalLineSymbol>>(
@ -221,14 +220,14 @@ namespace MalachScript::Parser {
// | // |
return Create<LexTokenImpl<LexTokenKind::VerticalLineSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::VerticalLineSymbol>>(TextSpan(start, start + 1));
} }
case u8'^': { case '^': {
auto n = Peek(); auto n = Peek();
if (n == u8'=') { if (n == '=') {
Progress(); Progress();
// ^= // ^=
return Create<LexTokenImpl<LexTokenKind::CaretEqualsSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::CaretEqualsSymbol>>(TextSpan(start, start + 2));
} }
if (n == u8'^') { if (n == '^') {
Progress(); Progress();
// ^^ // ^^
return Create<LexTokenImpl<LexTokenKind::CaretCaretSymbol>>(TextSpan(start, start + 2)); return Create<LexTokenImpl<LexTokenKind::CaretCaretSymbol>>(TextSpan(start, start + 2));
@ -236,21 +235,20 @@ namespace MalachScript::Parser {
// ^ // ^
return Create<LexTokenImpl<LexTokenKind::CaretSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::CaretSymbol>>(TextSpan(start, start + 1));
} }
case u8'~': return Create<LexTokenImpl<LexTokenKind::TildeSymbol>>(TextSpan(start, start + 1)); case '~': return Create<LexTokenImpl<LexTokenKind::TildeSymbol>>(TextSpan(start, start + 1));
case u8'.': return Create<LexTokenImpl<LexTokenKind::DotSymbol>>(TextSpan(start, start + 1)); case '.': return Create<LexTokenImpl<LexTokenKind::DotSymbol>>(TextSpan(start, start + 1));
case u8'[': case '[': return Create<LexTokenImpl<LexTokenKind::OpenBlockParenthesisSymbol>>(TextSpan(start, start + 1));
return Create<LexTokenImpl<LexTokenKind::OpenBlockParenthesisSymbol>>(TextSpan(start, start + 1)); case ']':
case u8']':
return Create<LexTokenImpl<LexTokenKind::CloseBlockParenthesisSymbol>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::CloseBlockParenthesisSymbol>>(TextSpan(start, start + 1));
case u8'@': return Create<LexTokenImpl<LexTokenKind::AtSymbol>>(TextSpan(start, start + 1)); case '@': return Create<LexTokenImpl<LexTokenKind::AtSymbol>>(TextSpan(start, start + 1));
case u8' ': case ' ':
case u8'\r': case '\r':
case u8'\n': case '\n':
case u8'\t': return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 1)); case '\t': return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 1));
// Byte order mark // Byte order mark
case u8'\xEF': { case '\xEF': {
if (Peek() == u8'\xBB' && Peek(2) == u8'\xBF') { if (Peek() == '\xBB' && Peek(2) == '\xBF') {
Progress(2); Progress(2);
return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 3)); return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 3));
} }
@ -258,22 +256,22 @@ namespace MalachScript::Parser {
{std::string(1, c)}); {std::string(1, c)});
return Create<LexTokenImpl<LexTokenKind::Unknown>>(TextSpan(start, start + 1)); return Create<LexTokenImpl<LexTokenKind::Unknown>>(TextSpan(start, start + 1));
} }
case u8'0': case '0':
case u8'1': case '1':
case u8'2': case '2':
case u8'3': case '3':
case u8'4': case '4':
case u8'5': case '5':
case u8'6': case '6':
case u8'7': case '7':
case u8'8': case '8':
case u8'9': return LexNumerical(c); case '9': return LexNumerical(c);
case u8'\'': return LexString(u8'\'', false); case '\'': return LexString('\'', false);
case u8'"': { case '"': {
if (Peek() == '"' && Peek(2) == '\"') { if (Peek() == '"' && Peek(2) == '\"') {
return LexString(u8'"', true); return LexString('"', true);
} }
return LexString(u8'"', false); return LexString('"', false);
} }
default: default:
@ -285,7 +283,7 @@ namespace MalachScript::Parser {
} }
} }
LexToken* Lexer::LexNumerical(char8_t c) { LexToken* Lexer::LexNumerical(char c) {
auto initialValue = LexDecimalValue(c); auto initialValue = LexDecimalValue(c);
auto numericalSystem = 10; // Default to decimal system. auto numericalSystem = 10; // Default to decimal system.
if (initialValue == 0) { if (initialValue == 0) {
@ -361,12 +359,12 @@ namespace MalachScript::Parser {
while (true) { while (true) {
auto v = (ParseInt)LexDecimalValue(Peek()); auto v = (ParseInt)LexDecimalValue(Peek());
if (v == 255) { if (v == 255) {
if (!isDecimal && Peek() == u8'.') { if (!isDecimal && Peek() == '.') {
isDecimal = true; isDecimal = true;
Progress(); Progress();
continue; continue;
} }
if (isDecimal && (Peek() == u8'e' || Peek() == u8'E')) { if (isDecimal && (Peek() == 'e' || Peek() == 'E')) {
isDecimal = false; isDecimal = false;
isExponent = true; isExponent = true;
Progress(); Progress();
@ -439,7 +437,7 @@ namespace MalachScript::Parser {
} }
return Create<IntegerLiteral>(TextSpan(start - 1, _position), value); return Create<IntegerLiteral>(TextSpan(start - 1, _position), value);
} }
StringLiteral* Lexer::LexString(char8_t opening, bool heredoc) { StringLiteral* Lexer::LexString(char opening, bool heredoc) {
auto openingPos = _position; auto openingPos = _position;
Progress(); Progress();
if (heredoc) { if (heredoc) {
@ -456,12 +454,12 @@ namespace MalachScript::Parser {
} else if (current == opening) { } else if (current == opening) {
break; break;
} }
if (current == u8'\0') { if (current == '\0') {
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset), LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset),
{"EndOfFile"}); {"EndOfFile"});
break; break;
} }
if (!heredoc && (current == u8'\n' || current == u8'\r')) { if (!heredoc && (current == '\n' || current == '\r')) {
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset), LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset),
{"Newline"}); {"Newline"});
break; break;
@ -486,139 +484,139 @@ namespace MalachScript::Parser {
Progress(offset - 1); Progress(offset - 1);
auto hash = Identifier::Hash(str); auto hash = Identifier::Hash(str);
switch (hash) { switch (hash) {
case Identifier::Hash(u8"and"): case Identifier::Hash("and"):
return Create<LexTokenImpl<LexTokenKind::AndKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::AndKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"abstract"): case Identifier::Hash("abstract"):
return Create<LexTokenImpl<LexTokenKind::AbstractKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::AbstractKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"auto"): case Identifier::Hash("auto"):
return Create<LexTokenImpl<LexTokenKind::AutoKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::AutoKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"bool"): case Identifier::Hash("bool"):
return Create<LexTokenImpl<LexTokenKind::BoolKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::BoolKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"break"): case Identifier::Hash("break"):
return Create<LexTokenImpl<LexTokenKind::BreakKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::BreakKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"case"): case Identifier::Hash("case"):
return Create<LexTokenImpl<LexTokenKind::CaseKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::CaseKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"cast"): case Identifier::Hash("cast"):
return Create<LexTokenImpl<LexTokenKind::CastKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::CastKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"catch"): case Identifier::Hash("catch"):
return Create<LexTokenImpl<LexTokenKind::CatchKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::CatchKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"class"): case Identifier::Hash("class"):
return Create<LexTokenImpl<LexTokenKind::ClassKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ClassKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"const"): case Identifier::Hash("const"):
return Create<LexTokenImpl<LexTokenKind::ConstKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ConstKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"continue"): case Identifier::Hash("continue"):
return Create<LexTokenImpl<LexTokenKind::ContinueKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ContinueKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"default"): case Identifier::Hash("default"):
return Create<LexTokenImpl<LexTokenKind::DefaultKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::DefaultKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"do"): case Identifier::Hash("do"):
return Create<LexTokenImpl<LexTokenKind::DoKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::DoKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"double"): case Identifier::Hash("double"):
return Create<LexTokenImpl<LexTokenKind::DoubleKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::DoubleKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"else"): case Identifier::Hash("else"):
return Create<LexTokenImpl<LexTokenKind::ElseKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ElseKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"enum"): case Identifier::Hash("enum"):
return Create<LexTokenImpl<LexTokenKind::EnumKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::EnumKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"explicit"): case Identifier::Hash("explicit"):
return Create<LexTokenImpl<LexTokenKind::ExplicitKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ExplicitKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"external"): case Identifier::Hash("external"):
return Create<LexTokenImpl<LexTokenKind::ExternalKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ExternalKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"false"): case Identifier::Hash("false"):
return Create<LexTokenImpl<LexTokenKind::FalseKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FalseKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"final"): case Identifier::Hash("final"):
return Create<LexTokenImpl<LexTokenKind::FinalKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FinalKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"float"): case Identifier::Hash("float"):
return Create<LexTokenImpl<LexTokenKind::FloatKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FloatKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"for"): case Identifier::Hash("for"):
return Create<LexTokenImpl<LexTokenKind::ForKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ForKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"from"): case Identifier::Hash("from"):
return Create<LexTokenImpl<LexTokenKind::FromKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FromKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"funcdef"): case Identifier::Hash("funcdef"):
return Create<LexTokenImpl<LexTokenKind::FuncdefKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FuncdefKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"function"): case Identifier::Hash("function"):
return Create<LexTokenImpl<LexTokenKind::FunctionKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::FunctionKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"get"): case Identifier::Hash("get"):
return Create<LexTokenImpl<LexTokenKind::GetKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::GetKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"if"): case Identifier::Hash("if"):
return Create<LexTokenImpl<LexTokenKind::IfKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::IfKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"import"): case Identifier::Hash("import"):
return Create<LexTokenImpl<LexTokenKind::ImportKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ImportKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"in"): case Identifier::Hash("in"):
return Create<LexTokenImpl<LexTokenKind::InKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::InKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"inout"): case Identifier::Hash("inout"):
return Create<LexTokenImpl<LexTokenKind::InoutKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::InoutKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"int"): case Identifier::Hash("int"):
return Create<LexTokenImpl<LexTokenKind::IntKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::IntKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"interface"): case Identifier::Hash("interface"):
return Create<LexTokenImpl<LexTokenKind::InterfaceKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::InterfaceKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"int8"): case Identifier::Hash("int8"):
return Create<LexTokenImpl<LexTokenKind::Int8Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Int8Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"int16"): case Identifier::Hash("int16"):
return Create<LexTokenImpl<LexTokenKind::Int16Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Int16Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"int32"): case Identifier::Hash("int32"):
return Create<LexTokenImpl<LexTokenKind::Int32Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Int32Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"int64"): case Identifier::Hash("int64"):
return Create<LexTokenImpl<LexTokenKind::Int64Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Int64Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"is"): case Identifier::Hash("is"):
return Create<LexTokenImpl<LexTokenKind::IsKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::IsKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"mixin"): case Identifier::Hash("mixin"):
return Create<LexTokenImpl<LexTokenKind::MixinKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::MixinKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"namespace"): case Identifier::Hash("namespace"):
return Create<LexTokenImpl<LexTokenKind::NamespaceKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::NamespaceKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"not"): case Identifier::Hash("not"):
return Create<LexTokenImpl<LexTokenKind::NotKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::NotKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"null"): case Identifier::Hash("null"):
return Create<LexTokenImpl<LexTokenKind::NullKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::NullKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"or"): case Identifier::Hash("or"):
return Create<LexTokenImpl<LexTokenKind::OrKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::OrKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"out"): case Identifier::Hash("out"):
return Create<LexTokenImpl<LexTokenKind::OutKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::OutKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"override"): case Identifier::Hash("override"):
return Create<LexTokenImpl<LexTokenKind::OverrideKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::OverrideKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"private"): case Identifier::Hash("private"):
return Create<LexTokenImpl<LexTokenKind::PrivateKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::PrivateKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"property"): case Identifier::Hash("property"):
return Create<LexTokenImpl<LexTokenKind::PropertyKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::PropertyKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"protected"): case Identifier::Hash("protected"):
return Create<LexTokenImpl<LexTokenKind::ProtectedKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ProtectedKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"return"): case Identifier::Hash("return"):
return Create<LexTokenImpl<LexTokenKind::ReturnKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ReturnKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"set"): case Identifier::Hash("set"):
return Create<LexTokenImpl<LexTokenKind::SetKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::SetKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"shared"): case Identifier::Hash("shared"):
return Create<LexTokenImpl<LexTokenKind::SharedKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::SharedKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"super"): case Identifier::Hash("super"):
return Create<LexTokenImpl<LexTokenKind::SuperKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::SuperKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"switch"): case Identifier::Hash("switch"):
return Create<LexTokenImpl<LexTokenKind::SwitchKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::SwitchKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"this"): case Identifier::Hash("this"):
return Create<LexTokenImpl<LexTokenKind::ThisKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::ThisKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"true"): case Identifier::Hash("true"):
return Create<LexTokenImpl<LexTokenKind::TrueKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::TrueKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"try"): case Identifier::Hash("try"):
return Create<LexTokenImpl<LexTokenKind::TryKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::TryKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"typedef"): case Identifier::Hash("typedef"):
return Create<LexTokenImpl<LexTokenKind::TypedefKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::TypedefKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"uint"): case Identifier::Hash("uint"):
return Create<LexTokenImpl<LexTokenKind::UintKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::UintKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"uint8"): case Identifier::Hash("uint8"):
return Create<LexTokenImpl<LexTokenKind::Uint8Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Uint8Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"uint16"): case Identifier::Hash("uint16"):
return Create<LexTokenImpl<LexTokenKind::Uint16Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Uint16Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"uint32"): case Identifier::Hash("uint32"):
return Create<LexTokenImpl<LexTokenKind::Uint32Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Uint32Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"uint64"): case Identifier::Hash("uint64"):
return Create<LexTokenImpl<LexTokenKind::Uint64Keyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::Uint64Keyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"void"): case Identifier::Hash("void"):
return Create<LexTokenImpl<LexTokenKind::VoidKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::VoidKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"while"): case Identifier::Hash("while"):
return Create<LexTokenImpl<LexTokenKind::WhileKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::WhileKeyword>>(TextSpan(start, _position));
case Identifier::Hash(u8"xor"): case Identifier::Hash("xor"):
return Create<LexTokenImpl<LexTokenKind::XorKeyword>>(TextSpan(start, _position)); return Create<LexTokenImpl<LexTokenKind::XorKeyword>>(TextSpan(start, _position));
default: return Create<IdentifierToken>(TextSpan(start, _position), Identifier(str.data(), offset, hash)); default: return Create<IdentifierToken>(TextSpan(start, _position), Identifier(str.data(), offset, hash));
} }
} }
bool Lexer::IsAlphaNumericalOrUnderscore(char8_t c) { bool Lexer::IsAlphaNumericalOrUnderscore(char c) {
if (c >= 'a' && c <= 'z') { if (c >= 'a' && c <= 'z') {
return true; return true;
} }

View File

@ -9,22 +9,22 @@
namespace MalachScript::Parser { namespace MalachScript::Parser {
class Lexer { class Lexer {
public: public:
Lexer(const char8_t* scriptName, const char8_t* script, Diagnostics::Logger* diag) Lexer(const char* scriptName, const char* script, Diagnostics::Logger* diag)
: Lexer(std::u8string_view(scriptName), std::u8string_view(script), diag) {} : Lexer(std::string_view(scriptName), std::string_view(script), diag) {}
Lexer(std::u8string_view scriptName, std::u8string_view script, Diagnostics::Logger* diag) Lexer(std::string_view scriptName, std::string_view script, Diagnostics::Logger* diag)
: _scriptName(scriptName), _script(script), _scriptLength(script.size()), _diagnostics(diag) {} : _scriptName(scriptName), _script(script), _scriptLength(script.size()), _diagnostics(diag) {}
const LexToken* Lex(); const LexToken* Lex();
private: private:
std::u8string_view _scriptName; std::string_view _scriptName;
std::u8string_view _script; std::string_view _script;
size_t _position = -1; size_t _position = -1;
size_t _scriptLength; size_t _scriptLength;
Diagnostics::Logger* _diagnostics; Diagnostics::Logger* _diagnostics;
Utils::MemoryPool<4096> _allocator; Utils::MemoryPool<4096> _allocator;
inline char8_t Consume() { inline char Consume() {
if (++_position >= _scriptLength) { if (++_position >= _scriptLength) {
return '\0'; return '\0';
} }
@ -33,7 +33,7 @@ namespace MalachScript::Parser {
inline void Progress(size_t steps = 1) { _position += steps; } inline void Progress(size_t steps = 1) { _position += steps; }
inline char8_t Peek(size_t offset = 1) { inline char Peek(size_t offset = 1) {
auto pos = _position + offset; auto pos = _position + offset;
if (pos >= _scriptLength) { if (pos >= _scriptLength) {
return '\0'; return '\0';
@ -42,16 +42,16 @@ namespace MalachScript::Parser {
} }
LexToken* LexNext(); LexToken* LexNext();
LexToken* LexNumerical(char8_t); LexToken* LexNumerical(char);
LexToken* LexDecimal(uint64_t initial); LexToken* LexDecimal(uint64_t initial);
IntegerLiteral* LexHexadecimal(); IntegerLiteral* LexHexadecimal();
IntegerLiteral* LexOctal(); IntegerLiteral* LexOctal();
IntegerLiteral* LexBinary(); IntegerLiteral* LexBinary();
StringLiteral* LexString(char8_t opening, bool heredoc); StringLiteral* LexString(char opening, bool heredoc);
LexToken* LexKeywordOrIdentifier(); LexToken* LexKeywordOrIdentifier();
static bool IsAlphaNumericalOrUnderscore(char8_t c); static bool IsAlphaNumericalOrUnderscore(char c);
template <class T, class... parameters> inline T* Create(parameters... args) { template <class T, class... parameters> inline T* Create(parameters... args) {
return _allocator.Create<T>(args...); return _allocator.Create<T>(args...);

View File

@ -1,66 +1,66 @@
#include "NumericalLexers.hpp" #include "NumericalLexers.hpp"
#include <cstdint> #include <cstdint>
uint8_t LexDecimalValue(char8_t c) { uint8_t LexDecimalValue(char c) {
switch (c) { switch (c) {
case u8'0': return 0; case '0': return 0;
case u8'1': return 1; case '1': return 1;
case u8'2': return 2; case '2': return 2;
case u8'3': return 3; case '3': return 3;
case u8'4': return 4; case '4': return 4;
case u8'5': return 5; case '5': return 5;
case u8'6': return 6; case '6': return 6;
case u8'7': return 7; case '7': return 7;
case u8'8': return 8; case '8': return 8;
case u8'9': return 9; case '9': return 9;
default: return 255; default: return 255;
} }
} }
uint8_t LexHexadecimalValue(char8_t c) { uint8_t LexHexadecimalValue(char c) {
switch (c) { switch (c) {
case u8'0': return 0; case '0': return 0;
case u8'1': return 1; case '1': return 1;
case u8'2': return 2; case '2': return 2;
case u8'3': return 3; case '3': return 3;
case u8'4': return 4; case '4': return 4;
case u8'5': return 5; case '5': return 5;
case u8'6': return 6; case '6': return 6;
case u8'7': return 7; case '7': return 7;
case u8'8': return 8; case '8': return 8;
case u8'9': return 9; case '9': return 9;
case u8'a': case 'a':
case u8'A': return 10; case 'A': return 10;
case u8'b': case 'b':
case u8'B': return 11; case 'B': return 11;
case u8'c': case 'c':
case u8'C': return 12; case 'C': return 12;
case u8'd': case 'd':
case u8'D': return 13; case 'D': return 13;
case u8'e': case 'e':
case u8'E': return 14; case 'E': return 14;
case u8'f': case 'f':
case u8'F': return 15; case 'F': return 15;
default: return 255; default: return 255;
} }
} }
uint8_t LexOctalValue(char8_t c) { uint8_t LexOctalValue(char c) {
switch (c) { switch (c) {
case u8'0': return 0; case '0': return 0;
case u8'1': return 1; case '1': return 1;
case u8'2': return 2; case '2': return 2;
case u8'3': return 3; case '3': return 3;
case u8'4': return 4; case '4': return 4;
case u8'5': return 5; case '5': return 5;
case u8'6': return 6; case '6': return 6;
case u8'7': return 7; case '7': return 7;
default: return 255; default: return 255;
} }
} }
uint8_t LexBinaryValue(char8_t c) { uint8_t LexBinaryValue(char c) {
switch (c) { switch (c) {
case u8'0': return 0; case '0': return 0;
case u8'1': return 1; case '1': return 1;
default: return 255; default: return 255;
} }
} }

View File

@ -3,9 +3,9 @@
#include <cstdint> #include <cstdint>
uint8_t LexDecimalValue(char8_t c); uint8_t LexDecimalValue(char c);
uint8_t LexHexadecimalValue(char8_t c); uint8_t LexHexadecimalValue(char c);
uint8_t LexOctalValue(char8_t c); uint8_t LexOctalValue(char c);
uint8_t LexBinaryValue(char8_t c); uint8_t LexBinaryValue(char c);
#endif // MALACHSCRIPT_NUMERICALLEXERS_HPP #endif // MALACHSCRIPT_NUMERICALLEXERS_HPP

View File

@ -38,7 +38,7 @@
namespace MalachScript::Parser { namespace MalachScript::Parser {
using namespace Diagnostics; using namespace Diagnostics;
const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, std::u8string_view scriptName, const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, std::string_view scriptName,
Logger* diagnostics) { Logger* diagnostics) {
const log_func& log = [diagnostics, scriptName](DiagnosticLevel level, DiagnosticType type, const log_func& log = [diagnostics, scriptName](DiagnosticLevel level, DiagnosticType type,
const TextSpan& span, const std::vector<std::string>& formats) { const TextSpan& span, const std::vector<std::string>& formats) {
@ -252,7 +252,7 @@ namespace MalachScript::Parser {
accessModifier = AccessModifier::Protected; accessModifier = AccessModifier::Protected;
PROGRESS_TOKEN(current); PROGRESS_TOKEN(current);
} }
ScopedPtr<const ParsedStatement> typeStatement = nullptr; ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
bool returnsReference = false; bool returnsReference = false;
if (current->GetKind() == LexTokenKind::TildeSymbol) { if (current->GetKind() == LexTokenKind::TildeSymbol) {
// TODO: Handle destructor // TODO: Handle destructor
@ -295,7 +295,8 @@ namespace MalachScript::Parser {
return true; return true;
} }
bool Parser::ParseType(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func& log) { bool Parser::ParseType(ScopedPtr<const ParsedTypeStatement>& out, const LexToken*& currentToken,
const log_func& log) {
const auto* current = currentToken; const auto* current = currentToken;
auto start = current->GetSpan().GetStart(); auto start = current->GetSpan().GetStart();
bool isConst = false; bool isConst = false;
@ -420,7 +421,7 @@ namespace MalachScript::Parser {
return true; return true;
} }
while (true) { while (true) {
ScopedPtr<const ParsedStatement> typeStatement = nullptr; ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
TypeMod typeMod = TypeMod::None; TypeMod typeMod = TypeMod::None;
Identifier identifier; Identifier identifier;
const ParsedStatement* defaultExpression = nullptr; const ParsedStatement* defaultExpression = nullptr;
@ -480,7 +481,7 @@ namespace MalachScript::Parser {
access = AccessModifier::Protected; access = AccessModifier::Protected;
PROGRESS_TOKEN(current); PROGRESS_TOKEN(current);
} }
ScopedPtr<const ParsedStatement> typeStatement = nullptr; ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
if (!ParseType(typeStatement, current, log)) { if (!ParseType(typeStatement, current, log)) {
return false; return false;
} }
@ -623,7 +624,7 @@ namespace MalachScript::Parser {
access = AccessModifier::Protected; access = AccessModifier::Protected;
PROGRESS_TOKEN(current); PROGRESS_TOKEN(current);
} }
ScopedPtr<const ParsedStatement> typeStatement = nullptr; ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
if (!ParseType(typeStatement, current, log)) { if (!ParseType(typeStatement, current, log)) {
return false; return false;
} }

View File

@ -11,7 +11,7 @@
namespace MalachScript::Parser { namespace MalachScript::Parser {
class Parser { class Parser {
public: public:
static const ParsedScriptStatement* Parse(const LexToken* firstToken, std::u8string_view scriptName, static const ParsedScriptStatement* Parse(const LexToken* firstToken, std::string_view scriptName,
Diagnostics::Logger* diagnostics); Diagnostics::Logger* diagnostics);
private: private:
@ -110,7 +110,8 @@ namespace MalachScript::Parser {
static bool ParsePrimType(Identifier& out, const LexToken*& currentToken, const log_func&); static bool ParsePrimType(Identifier& out, const LexToken*& currentToken, const log_func&);
static bool ParseDataType(Identifier& out, const LexToken*& currentToken, const log_func&); static bool ParseDataType(Identifier& out, const LexToken*& currentToken, const log_func&);
static bool ParseScope(std::vector<Identifier>& out, const LexToken*& currentToken, const log_func&); static bool ParseScope(std::vector<Identifier>& out, const LexToken*& currentToken, const log_func&);
static bool ParseType(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func&); static bool ParseType(ScopedPtr<const ParsedTypeStatement>& out, const LexToken*& currentToken,
const log_func&);
static bool ParseAssign(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func&); static bool ParseAssign(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func&);
// InitList // InitList
inline static bool ParsePreOp(PreOperator& op, const LexToken*& token, const log_func&) { inline static bool ParsePreOp(PreOperator& op, const LexToken*& token, const log_func&) {

View File

@ -5,6 +5,6 @@
using ParseInt = uintmax_t; using ParseInt = uintmax_t;
using ParseFloat = long double; using ParseFloat = long double;
using ParseString = std::u8string; using ParseString = std::string;
#endif // MALACHSCRIPT_PARSERDEFINES_HPP #endif // MALACHSCRIPT_PARSERDEFINES_HPP

View File

@ -1,6 +1,7 @@
#ifndef MALACHSCRIPT_PARSEDSTATEMENT_HPP #ifndef MALACHSCRIPT_PARSEDSTATEMENT_HPP
#define MALACHSCRIPT_PARSEDSTATEMENT_HPP #define MALACHSCRIPT_PARSEDSTATEMENT_HPP
#include <memory>
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <utility> #include <utility>
@ -8,6 +9,7 @@
#include "../../CoreData/AccessModifier.hpp" #include "../../CoreData/AccessModifier.hpp"
#include "../../CoreData/ClassAttr.hpp" #include "../../CoreData/ClassAttr.hpp"
#include "../../CoreData/FuncAttr.hpp" #include "../../CoreData/FuncAttr.hpp"
#include "../../CoreData/Identifier.hpp"
#include "../../CoreData/TypeMod.hpp" #include "../../CoreData/TypeMod.hpp"
#include "../../TextSpan.hpp" #include "../../TextSpan.hpp"
#include "ParsedStatementKind.hpp" #include "ParsedStatementKind.hpp"
@ -46,11 +48,12 @@ namespace MalachScript::Parser {
class ParsedClassStatement : public ParsedStatementImpl<ParsedStatementKind::Class> { class ParsedClassStatement : public ParsedStatementImpl<ParsedStatementKind::Class> {
public: public:
ParsedClassStatement(TextSpan span, ClassAttr classAttr, Identifier identifier, ParsedClassStatement(TextSpan span, ClassAttr classAttr, Identifier identifier,
std::vector<Identifier> inherits, const std::vector<const ParsedStatement*>& body) const std::vector<Identifier>& inherits, const std::vector<const ParsedStatement*>& body)
: ParsedStatementImpl<ParsedStatementKind::Class>(span), _classAttr(classAttr), _identifier(identifier), : ParsedStatementImpl<ParsedStatementKind::Class>(span), _classAttr(classAttr), _identifier(identifier),
_inherits(inherits), _body(body.size()) { _inherits(inherits), _body(body.size()) {
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]] ClassAttr GetClassAttr() const noexcept { return _classAttr; } [[nodiscard]] ClassAttr GetClassAttr() const noexcept { return _classAttr; }
@ -269,21 +272,21 @@ namespace MalachScript::Parser {
std::vector<std::unique_ptr<const ParsedStatement>> _statements; std::vector<std::unique_ptr<const ParsedStatement>> _statements;
}; };
class ParsedVarStatement : public ParsedStatementImpl<ParsedStatementKind::StatBlock> { class ParsedVarStatement : public ParsedStatementImpl<ParsedStatementKind::Var> {
public: public:
ParsedVarStatement(const TextSpan& span, AccessModifier access, const ParsedStatement* typeStatement, ParsedVarStatement(const TextSpan& span, AccessModifier access, const ParsedTypeStatement* typeStatement,
Identifier identifier) Identifier identifier)
: ParsedStatementImpl(span), _access(access), _typeStatement(typeStatement), _identifier(identifier) {} : ParsedStatementImpl(span), _access(access), _typeStatement(typeStatement), _identifier(identifier) {}
[[nodiscard]] AccessModifier GetAccess() const noexcept { return _access; } [[nodiscard]] AccessModifier GetAccess() const noexcept { return _access; }
[[nodiscard]] const std::unique_ptr<const ParsedStatement>& GetTypeStatement() const noexcept { [[nodiscard]] const std::unique_ptr<const ParsedTypeStatement>& GetTypeStatement() const noexcept {
return _typeStatement; return _typeStatement;
} }
[[nodiscard]] const Identifier& GetIdentifier() const noexcept { return _identifier; } [[nodiscard]] const Identifier& GetIdentifier() const noexcept { return _identifier; }
private: private:
AccessModifier _access; AccessModifier _access;
std::unique_ptr<const ParsedStatement> _typeStatement; std::unique_ptr<const ParsedTypeStatement> _typeStatement;
Identifier _identifier; Identifier _identifier;
}; };
@ -468,7 +471,6 @@ namespace MalachScript::Parser {
std::unique_ptr<const ParsedStatement> _expression; std::unique_ptr<const ParsedStatement> _expression;
std::vector<std::unique_ptr<const ParsedStatement>> _statements; std::vector<std::unique_ptr<const ParsedStatement>> _statements;
}; };
} }
#endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP #endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP

View File

@ -13,6 +13,7 @@ namespace MalachScript::Parser {
Func, Func,
VirtProp, VirtProp,
StatBlock, StatBlock,
Var,
If, If,
Assign, Assign,
BinaryExpression, BinaryExpression,
@ -46,6 +47,7 @@ namespace MalachScript::Parser {
case ParsedStatementKind::Func: return "Func"; case ParsedStatementKind::Func: return "Func";
case ParsedStatementKind::VirtProp: return "VirtProp"; case ParsedStatementKind::VirtProp: return "VirtProp";
case ParsedStatementKind::StatBlock: return "StatBlock"; case ParsedStatementKind::StatBlock: return "StatBlock";
case ParsedStatementKind::Var: return "Var";
case ParsedStatementKind::If: return "If"; case ParsedStatementKind::If: return "If";
case ParsedStatementKind::Assign: return "Assign"; case ParsedStatementKind::Assign: return "Assign";
case ParsedStatementKind::BinaryExpression: return "BinaryExpression"; case ParsedStatementKind::BinaryExpression: return "BinaryExpression";

View File

@ -193,6 +193,7 @@ namespace MalachScript::Parser {
case ParsedStatementKind::Try: break; case ParsedStatementKind::Try: break;
case ParsedStatementKind::Switch: break; case ParsedStatementKind::Switch: break;
case ParsedStatementKind::Case: break; case ParsedStatementKind::Case: break;
case ParsedStatementKind::Var: break;
} }
} }
}; };

1
src/ScriptEngine.cpp Normal file
View File

@ -0,0 +1 @@
#include "ScriptEngine.hpp"

11
src/ScriptEngine.hpp Normal file
View File

@ -0,0 +1,11 @@
#ifndef MALACHSCRIPT_SCRIPTENGINE_HPP
#define MALACHSCRIPT_SCRIPTENGINE_HPP
namespace MalachScript {
class ScriptEngine {
public:
private:
};
}
#endif // MALACHSCRIPT_SCRIPTENGINE_HPP

13
src/Utils/TreePrinter.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef MALACHSCRIPT_TREEPRINTER_HPP
#define MALACHSCRIPT_TREEPRINTER_HPP
#include <sstream>
class MalachScript::Utils {
class TreePrinter {
public:
private:
std::stringstream _stream;
};
};
#endif // MALACHSCRIPT_TREEPRINTER_HPP

View File

@ -6,7 +6,7 @@ using namespace MalachScript::Parser;
#define KEYWORD_TEST(script, symbol) \ #define KEYWORD_TEST(script, symbol) \
TEST_CASE("Lex " script) { \ TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \ auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
CHECK(token->GetKind() == LexTokenKind::symbol); \ CHECK(token->GetKind() == LexTokenKind::symbol); \
@ -79,10 +79,8 @@ KEYWORD_TEST("while", WhileKeyword);
KEYWORD_TEST("xor", XorKeyword); KEYWORD_TEST("xor", XorKeyword);
namespace doctest { namespace doctest {
template <> struct StringMaker<std::u8string> { template <> struct StringMaker<std::string> {
static String convert(const std::u8string& value) { static String convert(const std::string& value) { return String(reinterpret_cast<const char*>(value.data())); }
return String(reinterpret_cast<const char*>(value.data()));
}
}; };
template <> struct StringMaker<LexTokenKind> { template <> struct StringMaker<LexTokenKind> {
static String convert(LexTokenKind value) { return String(std::to_string((uint32_t)value).c_str()); } static String convert(LexTokenKind value) { return String(std::to_string((uint32_t)value).c_str()); }
@ -93,12 +91,12 @@ namespace doctest {
#define IDENTIFIER_TEST(identifier) \ #define IDENTIFIER_TEST(identifier) \
TEST_CASE("Lex identifier " identifier) { \ TEST_CASE("Lex identifier " identifier) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##identifier, u8##identifier, &diag); \ auto lexer = Lexer(identifier, identifier, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
REQUIRE(token->GetKind() == LexTokenKind::Identifier); \ REQUIRE(token->GetKind() == LexTokenKind::Identifier); \
auto value = ((IdentifierToken*)token)->GetValue().GetString(); \ auto value = ((IdentifierToken*)token)->GetValue().GetString(); \
CHECK(value == std::u8string(reinterpret_cast<const char8_t*>(identifier))); \ CHECK(value == std::string(reinterpret_cast<const char*>(identifier))); \
CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile); \ CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile); \
} }

View File

@ -6,7 +6,7 @@ using namespace MalachScript::Parser;
#define LEX_TEST(script, ...) \ #define LEX_TEST(script, ...) \
TEST_CASE("Lex: " script) { \ TEST_CASE("Lex: " script) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \ auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
std::vector<LexTokenKind> vec = {__VA_ARGS__, LexTokenKind::EndOfFile}; \ std::vector<LexTokenKind> vec = {__VA_ARGS__, LexTokenKind::EndOfFile}; \

View File

@ -6,7 +6,7 @@ using namespace MalachScript::Parser;
#define INTEGER_TEST(script, expected) \ #define INTEGER_TEST(script, expected) \
TEST_CASE("Lex " script) { \ TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \ auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
REQUIRE(token->GetKind() == LexTokenKind::IntegerLiteral); \ REQUIRE(token->GetKind() == LexTokenKind::IntegerLiteral); \
@ -18,7 +18,7 @@ using namespace MalachScript::Parser;
#define FLOAT_TEST(script, expected) \ #define FLOAT_TEST(script, expected) \
TEST_CASE("Lex " script) { \ TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \ auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
REQUIRE(token->GetKind() == LexTokenKind::FloatLiteral); \ REQUIRE(token->GetKind() == LexTokenKind::FloatLiteral); \

View File

@ -6,12 +6,12 @@ using namespace MalachScript::Parser;
#define STRING_TEST(str, constraint) \ #define STRING_TEST(str, constraint) \
TEST_CASE("Lex string " constraint str constraint) { \ TEST_CASE("Lex string " constraint str constraint) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##str, u8##constraint str constraint, &diag); \ auto lexer = Lexer(str, constraint str constraint, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
REQUIRE(token->GetKind() == LexTokenKind::StringLiteral); \ REQUIRE(token->GetKind() == LexTokenKind::StringLiteral); \
auto value = ((const StringLiteral*)token)->GetValue(); \ auto value = ((const StringLiteral*)token)->GetValue(); \
CHECK(value == std::u8string(reinterpret_cast<const char8_t*>(str))); \ CHECK(value == std::string(reinterpret_cast<const char*>(str))); \
CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile); \ CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile); \
} }
@ -23,14 +23,14 @@ STRING_TEST("\"\"foo bar\"\"", "\"\"\"");
TEST_CASE("Lex multiline string") { TEST_CASE("Lex multiline string") {
MalachScript::Diagnostics::Logger diag; MalachScript::Diagnostics::Logger diag;
auto lexer = Lexer(u8"multiline", u8R"("""foo auto lexer = Lexer("multiline", R"("""foo
bar""")", bar""")",
&diag); &diag);
const auto* token = lexer.Lex(); const auto* token = lexer.Lex();
CHECK(diag.GetMessages().empty()); CHECK(diag.GetMessages().empty());
REQUIRE(token->GetKind() == LexTokenKind::StringLiteral); REQUIRE(token->GetKind() == LexTokenKind::StringLiteral);
auto value = (dynamic_cast<const StringLiteral*>(token))->GetValue(); auto value = (dynamic_cast<const StringLiteral*>(token))->GetValue();
CHECK(value == std::u8string(reinterpret_cast<const char8_t*>(R"(foo CHECK(value == std::string(reinterpret_cast<const char*>(R"(foo
bar)"))); bar)")));
CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile); CHECK(token->GetNext()->GetKind() == LexTokenKind::EndOfFile);
} }

View File

@ -7,7 +7,7 @@ using namespace MalachScript::Parser;
#define SYMBOL_TEST(script, symbol) \ #define SYMBOL_TEST(script, symbol) \
TEST_CASE("Lex " script) { \ TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \ MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \ auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \ const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \ CHECK(diag.GetMessages().empty()); \
CHECK(token->GetKind() == LexTokenKind::symbol); \ CHECK(token->GetKind() == LexTokenKind::symbol); \
@ -71,10 +71,10 @@ SYMBOL_TEST(" ", Whitespace)
#undef SYMBOL_TEST #undef SYMBOL_TEST
TEST_CASE("Lex whitespace") { TEST_CASE("Lex whitespace") {
auto whitespace = {u8" ", u8"\t", u8"\n", u8"\r", u8"\xef\xbb\xbf"}; auto whitespace = {" ", "\t", "\n", "\r", "\xef\xbb\xbf"};
for (const auto* v : whitespace) { for (const auto* v : whitespace) {
MalachScript::Diagnostics::Logger diag; MalachScript::Diagnostics::Logger diag;
auto lexer = Lexer(u8"whitespace", v, &diag); auto lexer = Lexer("whitespace", v, &diag);
const auto* token = lexer.Lex(); const auto* token = lexer.Lex();
CHECK(diag.GetMessages().empty()); CHECK(diag.GetMessages().empty());
CHECK(token->GetKind() == LexTokenKind::Whitespace); CHECK(token->GetKind() == LexTokenKind::Whitespace);

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \ vec[i]->SetNext(vec[i + 1]); \
} \ } \
Diagnostics::Logger diags; \ Diagnostics::Logger diags; \
auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ auto* script = Parser::Parser::Parse(vec.front(), "scriptname", &diags); \
REQUIRE(diags.GetMessages().empty()); \ REQUIRE(diags.GetMessages().empty()); \
asserts; \ asserts; \
delete vec[0]; \ delete vec[0]; \
@ -24,7 +24,7 @@ using namespace MalachScript;
PARSER_TEST("Parse basic class without body", PARSER_TEST("Parse basic class without body",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
{ {
REQUIRE(script->GetStatements().size() == 1); REQUIRE(script->GetStatements().size() == 1);
@ -34,7 +34,7 @@ PARSER_TEST("Parse basic class without body",
PARSER_TEST("Parse basic class without body with whitespaces", PARSER_TEST("Parse basic class without body with whitespaces",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
{ {
@ -45,7 +45,7 @@ PARSER_TEST("Parse basic class without body with whitespaces",
PARSER_TEST( PARSER_TEST(
"Parse basic class with empty body", "Parse basic class with empty body",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))),
{ {

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \ vec[i]->SetNext(vec[i + 1]); \
} \ } \
Diagnostics::Logger diags; \ Diagnostics::Logger diags; \
auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ auto* script = Parser::Parser::Parse(vec.front(), "scriptname", &diags); \
REQUIRE(diags.GetMessages().empty()); \ REQUIRE(diags.GetMessages().empty()); \
asserts; \ asserts; \
delete vec[0]; \ delete vec[0]; \
@ -25,7 +25,7 @@ using namespace MalachScript;
PARSER_TEST("Parse ``void foobar();``", PARSER_TEST("Parse ``void foobar();``",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::VoidKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::VoidKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
@ -41,9 +41,9 @@ PARSER_TEST("Parse ``void foobar();``",
CHECK_FALSE(type->IsArray()); CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle()); CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier(); auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"void"); CHECK(id.GetIdentifier().GetString() == "void");
CHECK_FALSE(funcStat->ReturnsReference()); CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().empty()); CHECK(paramList->GetParameters().empty());
CHECK_FALSE(funcStat->IsConst()); CHECK_FALSE(funcStat->IsConst());
@ -52,13 +52,13 @@ PARSER_TEST("Parse ``void foobar();``",
}) })
PARSER_TEST("Parse scoped function without body.", PARSER_TEST("Parse scoped function without body.",
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"), new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"), new Parser::IdentifierToken(TextSpan(0, 0), "baz"),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
@ -74,11 +74,11 @@ PARSER_TEST("Parse scoped function without body.",
CHECK_FALSE(type->IsArray()); CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle()); CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier(); auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz"); CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == u8"bar"); CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == u8"foo"); CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference()); CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().empty()); CHECK(paramList->GetParameters().empty());
CHECK_FALSE(funcStat->IsConst()); CHECK_FALSE(funcStat->IsConst());
@ -87,24 +87,24 @@ PARSER_TEST("Parse scoped function without body.",
}) })
PARSER_TEST("Parse scoped function with parameters without body.", PARSER_TEST("Parse scoped function with parameters without body.",
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"), new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"), new Parser::IdentifierToken(TextSpan(0, 0), "baz"),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"par1"), new Parser::IdentifierToken(TextSpan(0, 0), "par1"),
new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::BoolKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::BoolKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"par2"), new Parser::IdentifierToken(TextSpan(0, 0), "par2"),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
@ -120,11 +120,11 @@ PARSER_TEST("Parse scoped function with parameters without body.",
CHECK_FALSE(type->IsArray()); CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle()); CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier(); auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz"); CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == u8"bar"); CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == u8"foo"); CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference()); CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().size() == 2); CHECK(paramList->GetParameters().size() == 2);
@ -133,9 +133,9 @@ PARSER_TEST("Parse scoped function with parameters without body.",
CHECK_FALSE(par1.GetTypeStatement()->IsArray()); CHECK_FALSE(par1.GetTypeStatement()->IsArray());
CHECK_FALSE(par1.GetTypeStatement()->IsHandle()); CHECK_FALSE(par1.GetTypeStatement()->IsHandle());
auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier(); auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier();
CHECK(par1TypeId.GetIdentifier().GetString() == u8"int"); CHECK(par1TypeId.GetIdentifier().GetString() == "int");
CHECK(par1.GetTypeMod() == TypeMod::None); CHECK(par1.GetTypeMod() == TypeMod::None);
CHECK(par1.GetIdentifier().GetString() == u8"par1"); CHECK(par1.GetIdentifier().GetString() == "par1");
CHECK(par1.GetDefaultExpression() == nullptr); CHECK(par1.GetDefaultExpression() == nullptr);
auto& par2 = *paramList->GetParameters()[1]; auto& par2 = *paramList->GetParameters()[1];
@ -143,9 +143,9 @@ PARSER_TEST("Parse scoped function with parameters without body.",
CHECK_FALSE(par2.GetTypeStatement()->IsArray()); CHECK_FALSE(par2.GetTypeStatement()->IsArray());
CHECK_FALSE(par2.GetTypeStatement()->IsHandle()); CHECK_FALSE(par2.GetTypeStatement()->IsHandle());
auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier(); auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier();
CHECK(par2TypeId.GetIdentifier().GetString() == u8"bool"); CHECK(par2TypeId.GetIdentifier().GetString() == "bool");
CHECK(par2.GetTypeMod() == TypeMod::None); CHECK(par2.GetTypeMod() == TypeMod::None);
CHECK(par2.GetIdentifier().GetString() == u8"par2"); CHECK(par2.GetIdentifier().GetString() == "par2");
CHECK(par2.GetDefaultExpression() == nullptr); CHECK(par2.GetDefaultExpression() == nullptr);
CHECK_FALSE(funcStat->IsConst()); CHECK_FALSE(funcStat->IsConst());
@ -154,20 +154,20 @@ PARSER_TEST("Parse scoped function with parameters without body.",
}) })
PARSER_TEST("Parse scoped function with reference parameters without body.", PARSER_TEST("Parse scoped function with reference parameters without body.",
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"), new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"), new Parser::IdentifierToken(TextSpan(0, 0), "baz"),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::InKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::InKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"par1"), new Parser::IdentifierToken(TextSpan(0, 0), "par1"),
new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)),
@ -175,7 +175,7 @@ PARSER_TEST("Parse scoped function with reference parameters without body.",
new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OutKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OutKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"par2"), new Parser::IdentifierToken(TextSpan(0, 0), "par2"),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
@ -191,11 +191,11 @@ PARSER_TEST("Parse scoped function with reference parameters without body.",
CHECK_FALSE(type->IsArray()); CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle()); CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier(); auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz"); CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == u8"bar"); CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == u8"foo"); CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference()); CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().size() == 2); CHECK(paramList->GetParameters().size() == 2);
@ -204,9 +204,9 @@ PARSER_TEST("Parse scoped function with reference parameters without body.",
CHECK_FALSE(par1.GetTypeStatement()->IsArray()); CHECK_FALSE(par1.GetTypeStatement()->IsArray());
CHECK_FALSE(par1.GetTypeStatement()->IsHandle()); CHECK_FALSE(par1.GetTypeStatement()->IsHandle());
auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier(); auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier();
CHECK(par1TypeId.GetIdentifier().GetString() == u8"int"); CHECK(par1TypeId.GetIdentifier().GetString() == "int");
CHECK(par1.GetTypeMod() == TypeMod::RefIn); CHECK(par1.GetTypeMod() == TypeMod::RefIn);
CHECK(par1.GetIdentifier().GetString() == u8"par1"); CHECK(par1.GetIdentifier().GetString() == "par1");
CHECK(par1.GetDefaultExpression() == nullptr); CHECK(par1.GetDefaultExpression() == nullptr);
auto& par2 = *paramList->GetParameters()[1]; auto& par2 = *paramList->GetParameters()[1];
@ -214,9 +214,9 @@ PARSER_TEST("Parse scoped function with reference parameters without body.",
CHECK_FALSE(par2.GetTypeStatement()->IsArray()); CHECK_FALSE(par2.GetTypeStatement()->IsArray());
CHECK_FALSE(par2.GetTypeStatement()->IsHandle()); CHECK_FALSE(par2.GetTypeStatement()->IsHandle());
auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier(); auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier();
CHECK(par2TypeId.GetIdentifier().GetString() == u8"bool"); CHECK(par2TypeId.GetIdentifier().GetString() == "bool");
CHECK(par2.GetTypeMod() == TypeMod::RefOut); CHECK(par2.GetTypeMod() == TypeMod::RefOut);
CHECK(par2.GetIdentifier().GetString() == u8"par2"); CHECK(par2.GetIdentifier().GetString() == "par2");
CHECK(par2.GetDefaultExpression() == nullptr); CHECK(par2.GetDefaultExpression() == nullptr);
CHECK_FALSE(funcStat->IsConst()); CHECK_FALSE(funcStat->IsConst());

View File

@ -7,9 +7,9 @@ using namespace MalachScript;
#define PARSE_TEST(name, scriptText, asserts) \ #define PARSE_TEST(name, scriptText, asserts) \
TEST_CASE(name) { \ TEST_CASE(name) { \
Diagnostics::Logger diags; \ Diagnostics::Logger diags; \
auto lexer = Parser::Lexer(u8##name, u8##scriptText, &diags); \ auto lexer = Parser::Lexer(name, scriptText, &diags); \
auto token = lexer.Lex(); \ auto token = lexer.Lex(); \
auto script = Parser::Parser::Parse(token, u8##name, &diags); \ auto script = Parser::Parser::Parse(token, name, &diags); \
asserts; \ asserts; \
delete script; \ delete script; \
} }
@ -42,7 +42,7 @@ PARSE_TEST("Parse class with virtprop", "class foobar { private bool foo { get;
REQUIRE(firstClassStatement->GetKind() == Parser::ParsedStatementKind::VirtProp); REQUIRE(firstClassStatement->GetKind() == Parser::ParsedStatementKind::VirtProp);
auto virtPropStatement = dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement); auto virtPropStatement = dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Private); REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Private);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo"); REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet()); REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet()); REQUIRE(virtPropStatement->HasSet());
REQUIRE(virtPropStatement->GetGetStatement() == nullptr); REQUIRE(virtPropStatement->GetGetStatement() == nullptr);

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \ vec[i]->SetNext(vec[i + 1]); \
} \ } \
Diagnostics::Logger diags; \ Diagnostics::Logger diags; \
auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ auto* script = Parser::Parser::Parse(vec.front(), "scriptname", &diags); \
REQUIRE(diags.GetMessages().empty()); \ REQUIRE(diags.GetMessages().empty()); \
asserts; \ asserts; \
delete vec[0]; \ delete vec[0]; \
@ -25,10 +25,10 @@ using namespace MalachScript;
PARSER_TEST( PARSER_TEST(
"Parse class foobar { bool foo { get; set; } }", "Parse class foobar { bool foo { get; set; } }",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bool"), new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
@ -46,7 +46,7 @@ PARSER_TEST(
auto virtPropStatement = auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement); dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public); REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo"); REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet()); REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet()); REQUIRE(virtPropStatement->HasSet());
REQUIRE_FALSE(virtPropStatement->IsGetConst()); REQUIRE_FALSE(virtPropStatement->IsGetConst());
@ -58,10 +58,10 @@ PARSER_TEST(
PARSER_TEST( PARSER_TEST(
"Parse class foobar { bool foo { get const; set const; } }", "Parse class foobar { bool foo { get const; set const; } }",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bool"), new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)),
@ -81,7 +81,7 @@ PARSER_TEST(
auto virtPropStatement = auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement); dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public); REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo"); REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet()); REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet()); REQUIRE(virtPropStatement->HasSet());
REQUIRE(virtPropStatement->IsGetConst()); REQUIRE(virtPropStatement->IsGetConst());
@ -93,10 +93,10 @@ PARSER_TEST(
PARSER_TEST( PARSER_TEST(
"Parse class foobar { bool foo { get const override; set const override; } }", "Parse class foobar { bool foo { get const override; set const override; } }",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bool"), new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)),
@ -118,7 +118,7 @@ PARSER_TEST(
auto virtPropStatement = auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement); dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public); REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo"); REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet()); REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet()); REQUIRE(virtPropStatement->HasSet());
REQUIRE(virtPropStatement->IsGetConst()); REQUIRE(virtPropStatement->IsGetConst());
@ -145,48 +145,47 @@ PARSER_TEST(
PARSER_TEST( PARSER_TEST(
"Virtprops with bodies", "Virtprops with bodies",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)), PARSER_TEST_TOKENS(
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"int"), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"i"), new Parser::IdentifierToken(TextSpan(0, 0), "int"), new Parser::IdentifierToken(TextSpan(0, 0), "i"),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"bool"), new Parser::IdentifierToken(TextSpan(0, 0), "bool"), new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::IfKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::IfKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::TrueKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::TrueKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ReturnKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ReturnKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::TrueKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::TrueKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::ReturnKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ReturnKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::FalseKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::FalseKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SetKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::IfKeyword>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::IfKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IntegerLiteral(TextSpan(0, 0), 1), new Parser::IntegerLiteral(TextSpan(0, 0), 1),
new Parser::LexTokenImpl<Parser::LexTokenKind::EqualsEqualsSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::EqualsEqualsSymbol>(TextSpan(0, 0)),
new Parser::IntegerLiteral(TextSpan(0, 0), 1), new Parser::IntegerLiteral(TextSpan(0, 0), 1),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"i"), new Parser::IdentifierToken(TextSpan(0, 0), "i"),
new Parser::LexTokenImpl<Parser::LexTokenKind::PlusPlusSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::PlusPlusSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"i"), new Parser::IdentifierToken(TextSpan(0, 0), "i"),
new Parser::LexTokenImpl<Parser::LexTokenKind::MinusMinusSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::MinusMinusSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))), new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))),
{ {
REQUIRE(script->GetStatements().size() == 1); REQUIRE(script->GetStatements().size() == 1);
auto firstStatement = script->GetStatements()[0].get(); auto firstStatement = script->GetStatements()[0].get();
@ -197,7 +196,7 @@ PARSER_TEST(
auto virtPropStatement = auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement); dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public); REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo"); REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet()); REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet()); REQUIRE(virtPropStatement->HasSet());
REQUIRE_FALSE(virtPropStatement->IsGetConst()); REQUIRE_FALSE(virtPropStatement->IsGetConst());