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)
endif ()
file(GLOB_RECURSE SRC_FILES "src/*.cpp" "src/*.hpp")
file(GLOB_RECURSE SRC_FILES "src/*.cpp")
add_library(MalachScript SHARED ${SRC_FILES})
set(LINKS)

View File

@ -9,14 +9,14 @@ namespace MalachScriptRepl {
private:
WINDOW* _window;
std::vector<std::u8string> _lines = {u8""};
std::vector<std::string> _lines = {""};
int _row = 0;
int _col = 0;
int _rightPos = 0;
int _scroll = 0;
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;
public:
@ -26,7 +26,7 @@ namespace MalachScriptRepl {
_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;
}
@ -99,7 +99,7 @@ namespace MalachScriptRepl {
}
inline void Return() {
_lines.insert(_lines.begin() + _row + _scroll + 1, u8"");
_lines.insert(_lines.begin() + _row + _scroll + 1, "");
if (_row >= _lineCount - 1) {
ScrollDown();
} else {
@ -119,10 +119,10 @@ namespace MalachScriptRepl {
wclrtoeol(_window);
auto& line = _lines[_row + _scroll];
if ((int)line.length() <= _col) {
line += u8" ";
line += " ";
} else {
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());
@ -148,7 +148,7 @@ namespace MalachScriptRepl {
wmove(_window, _row, 0);
auto& line = _lines[_row + _scroll];
if ((int)line.length() <= _col) {
line += (char8_t)c;
line += (char)c;
} else {
line.insert(line.begin() + _col, c);
}
@ -160,7 +160,7 @@ namespace MalachScriptRepl {
}
inline void ResetText() {
std::u8string script;
std::string script;
for (size_t i = 0; i < _lines.size(); i++) {
script += _lines[i];
if (i != _lines.size() - 1) {
@ -196,11 +196,11 @@ namespace MalachScriptRepl {
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;
auto yx = GetCursorPosition();
Clear();
script += u8" ";
script += " ";
size_t linenum = 0;
size_t index = 0;

View File

@ -7,9 +7,9 @@
#include "../src/Parser/Statements/ParsedStatementStringifier.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) {
std::u8string script;
std::string script;
for (size_t i = 0; i < lines.size(); i++) {
script += lines[i];
if (i != lines.size() - 1) {
@ -23,9 +23,9 @@ void ParseAndUpdate(const std::vector<std::u8string>& lines, WINDOW* diagnostics
outfile.close();
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* 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;
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);
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);
});

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
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace MalachScript {
constexpr static uint32_t crc_table[256] = {
@ -35,28 +38,30 @@ namespace MalachScript {
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
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 {
const char8_t* _str;
const char* _str;
size_t _length;
uint32_t _hash;
public:
Identifier() : _str(nullptr), _length(0), _hash(0) {}
constexpr Identifier(const char8_t* 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) : _str(c), _length(CalcLength(c)), _hash(Hash(c)) {}
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 std::u8string_view GetString() const noexcept {
return std::u8string_view(_str, _length);
[[nodiscard]] constexpr inline std::string_view GetString() const noexcept {
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; }
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;
for (auto c : sv) {
crc = (crc >> 8) ^ crc_table[(crc ^ c) & 0xff];
@ -64,6 +69,9 @@ namespace MalachScript {
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) {
out << std::string((const char*)c._str, c._length);
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

View File

@ -2,6 +2,7 @@
#define MALACHSCRIPT_PRIMITIVETYPES_HPP
#include <string>
#include "../Binder/BoundType.hpp"
#include "Identifier.hpp"
#if !__cpp_constinit
@ -9,22 +10,34 @@
#endif
namespace MalachScript {
static constinit Identifier _voidName = u8"void";
static constinit Identifier _intName = u8"int";
static constinit Identifier _int8Name = u8"int8";
static constinit Identifier _int16Name = u8"int16";
static constinit Identifier _int32Name = u8"int32";
static constinit Identifier _int64Name = u8"int64";
static constinit Identifier _uintName = u8"uint";
static constinit Identifier _uint8Name = u8"uint8";
static constinit Identifier _uint16Name = u8"uint16";
static constinit Identifier _uint32Name = u8"uint32";
static constinit Identifier _uint64Name = u8"uint64";
static constinit Identifier _floatName = u8"float";
static constinit Identifier _doubleName = u8"double";
static constinit Identifier _boolName = u8"bool";
static constinit Identifier _voidName = "void";
static constinit Identifier _intName = "int";
static constinit Identifier _int8Name = "int8";
static constinit Identifier _int16Name = "int16";
static constinit Identifier _int32Name = "int32";
static constinit Identifier _int64Name = "int64";
static constinit Identifier _uintName = "uint";
static constinit Identifier _uint8Name = "uint8";
static constinit Identifier _uint16Name = "uint16";
static constinit Identifier _uint32Name = "uint32";
static constinit Identifier _uint64Name = "uint64";
static constinit Identifier _floatName = "float";
static constinit Identifier _doubleName = "double";
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 {
public:
@ -43,6 +56,20 @@ namespace MalachScript {
constexpr static const Identifier& DoubleName() noexcept { return _doubleName; }
constexpr static const Identifier& BoolName() noexcept { return _boolName; }
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 {
DiagnosticLevel _level;
DiagnosticType _type;
std::u8string_view _scriptName;
std::string_view _scriptName;
TextSpan _span;
std::vector<std::string> _formats;
public:
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::u8string_view& scriptName,
TextSpan span, const std::vector<std::string>& formats = {})
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::string_view& scriptName, TextSpan span,
const std::vector<std::string>& formats = {})
: _level(level), _type(type), _scriptName(scriptName), _span(span), _formats(formats) {}
[[nodiscard]] inline DiagnosticLevel GetLevel() const noexcept { return _level; }
[[nodiscard]] inline DiagnosticType GetType() const noexcept { return _type; }
[[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; }
};
}

View File

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

View File

@ -23,6 +23,8 @@ namespace MalachScript::Diagnostics {
diag->GetFormats());
}
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());
}

View File

@ -9,24 +9,24 @@ namespace MalachScript::Diagnostics {
std::vector<Diagnostic> _messages;
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 = {}) {
_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);
}
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);
}
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);
}
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 = {}) {
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);
}

View File

@ -25,13 +25,13 @@ namespace MalachScript::Parser {
auto start = _position;
auto c = Consume();
switch (c) {
case u8'\0': return Create<LexTokenImpl<LexTokenKind::EndOfFile>>(TextSpan(start + 1, start + 2));
case u8'*': {
case '\0': return Create<LexTokenImpl<LexTokenKind::EndOfFile>>(TextSpan(start + 1, start + 2));
case '*': {
auto n = Peek();
if (n == u8'*') {
if (n == '*') {
Progress();
n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// **=
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));
}
if (n == u8'=') {
if (n == '=') {
Progress();
// *=
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));
}
case u8'/':
if (Peek() == u8'=') {
case '/':
if (Peek() == '=') {
Progress();
// /=
return Create<LexTokenImpl<LexTokenKind::SlashEqualsSymbol>>(TextSpan(start, start + 2));
}
// /
return Create<LexTokenImpl<LexTokenKind::SlashSymbol>>(TextSpan(start, start + 1));
case u8'%':
if (Peek() == u8'=') {
case '%':
if (Peek() == '=') {
Progress();
// %=
return Create<LexTokenImpl<LexTokenKind::PercentEqualsSymbol>>(TextSpan(start, start + 2));
}
// %
return Create<LexTokenImpl<LexTokenKind::PercentSymbol>>(TextSpan(start, start + 1));
case u8'+': {
case '+': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// +=
return Create<LexTokenImpl<LexTokenKind::PlusEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'+') {
if (n == '+') {
Progress();
// ++
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));
}
case u8'-': {
case '-': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// -=
return Create<LexTokenImpl<LexTokenKind::MinusEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'-') {
if (n == '-') {
Progress();
// --
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));
}
case u8'<': {
case '<': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// <=
return Create<LexTokenImpl<LexTokenKind::LessThanEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'<') {
if (n == '<') {
Progress();
if (Peek() == u8'=') {
if (Peek() == '=') {
Progress();
// <<=
return Create<LexTokenImpl<LexTokenKind::LessThanLessThanEqualsSymbol>>(
@ -114,25 +114,25 @@ namespace MalachScript::Parser {
// <
return Create<LexTokenImpl<LexTokenKind::LessThanSymbol>>(TextSpan(start, start + 1));
}
case u8'>': {
case '>': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// >=
return Create<LexTokenImpl<LexTokenKind::GreaterThanEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'>') {
if (n == '>') {
Progress();
n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// >>=
return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanEqualsSymbol>>(
TextSpan(start, start + 3));
}
if (n == u8'>') {
if (n == '>') {
Progress();
if (Peek() == u8'=') {
if (Peek() == '=') {
Progress();
// >>>=
return Create<LexTokenImpl<LexTokenKind::GreaterThanGreaterThanGreaterThanEqualsSymbol>>(
@ -148,10 +148,10 @@ namespace MalachScript::Parser {
// >
return Create<LexTokenImpl<LexTokenKind::GreaterThanSymbol>>(TextSpan(start, start + 1));
}
case u8'(': return Create<LexTokenImpl<LexTokenKind::OpenParenthesisSymbol>>(TextSpan(start, start + 1));
case u8')': return Create<LexTokenImpl<LexTokenKind::CloseParenthesisSymbol>>(TextSpan(start, start + 1));
case u8'=': {
if (Peek() == u8'=') {
case '(': return Create<LexTokenImpl<LexTokenKind::OpenParenthesisSymbol>>(TextSpan(start, start + 1));
case ')': return Create<LexTokenImpl<LexTokenKind::CloseParenthesisSymbol>>(TextSpan(start, start + 1));
case '=': {
if (Peek() == '=') {
Progress();
// ==
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));
}
case u8'!': {
case '!': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// !=
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);
// !is
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));
}
case u8'?': return Create<LexTokenImpl<LexTokenKind::QuestionMarkSymbol>>(TextSpan(start, start + 1));
case u8':': {
if (Peek() == u8':') {
case '?': return Create<LexTokenImpl<LexTokenKind::QuestionMarkSymbol>>(TextSpan(start, start + 1));
case ':': {
if (Peek() == ':') {
Progress();
// ::
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));
}
case u8'&': {
case '&': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// &=
return Create<LexTokenImpl<LexTokenKind::AmpersandEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'&') {
if (n == '&') {
Progress();
// &&
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));
}
case u8',': return Create<LexTokenImpl<LexTokenKind::CommaSymbol>>(TextSpan(start, start + 1));
case u8'{':
return Create<LexTokenImpl<LexTokenKind::OpenCurlyParenthesisSymbol>>(TextSpan(start, start + 1));
case u8'}':
case ',': return Create<LexTokenImpl<LexTokenKind::CommaSymbol>>(TextSpan(start, start + 1));
case '{': return Create<LexTokenImpl<LexTokenKind::OpenCurlyParenthesisSymbol>>(TextSpan(start, start + 1));
case '}':
return Create<LexTokenImpl<LexTokenKind::CloseCurlyParenthesisSymbol>>(TextSpan(start, start + 1));
case u8';': return Create<LexTokenImpl<LexTokenKind::SemicolonSymbol>>(TextSpan(start, start + 1));
case u8'|': {
case ';': return Create<LexTokenImpl<LexTokenKind::SemicolonSymbol>>(TextSpan(start, start + 1));
case '|': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// |=
return Create<LexTokenImpl<LexTokenKind::VerticalLineEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'|') {
if (n == '|') {
Progress();
// ||
return Create<LexTokenImpl<LexTokenKind::VerticalLineVerticalLineSymbol>>(
@ -221,14 +220,14 @@ namespace MalachScript::Parser {
// |
return Create<LexTokenImpl<LexTokenKind::VerticalLineSymbol>>(TextSpan(start, start + 1));
}
case u8'^': {
case '^': {
auto n = Peek();
if (n == u8'=') {
if (n == '=') {
Progress();
// ^=
return Create<LexTokenImpl<LexTokenKind::CaretEqualsSymbol>>(TextSpan(start, start + 2));
}
if (n == u8'^') {
if (n == '^') {
Progress();
// ^^
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));
}
case u8'~': return Create<LexTokenImpl<LexTokenKind::TildeSymbol>>(TextSpan(start, start + 1));
case u8'.': return Create<LexTokenImpl<LexTokenKind::DotSymbol>>(TextSpan(start, start + 1));
case u8'[':
return Create<LexTokenImpl<LexTokenKind::OpenBlockParenthesisSymbol>>(TextSpan(start, start + 1));
case u8']':
case '~': return Create<LexTokenImpl<LexTokenKind::TildeSymbol>>(TextSpan(start, start + 1));
case '.': return Create<LexTokenImpl<LexTokenKind::DotSymbol>>(TextSpan(start, start + 1));
case '[': return Create<LexTokenImpl<LexTokenKind::OpenBlockParenthesisSymbol>>(TextSpan(start, start + 1));
case ']':
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 u8'\r':
case u8'\n':
case u8'\t': return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 1));
case ' ':
case '\r':
case '\n':
case '\t': return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 1));
// Byte order mark
case u8'\xEF': {
if (Peek() == u8'\xBB' && Peek(2) == u8'\xBF') {
case '\xEF': {
if (Peek() == '\xBB' && Peek(2) == '\xBF') {
Progress(2);
return Create<LexTokenImpl<LexTokenKind::Whitespace>>(TextSpan(start, start + 3));
}
@ -258,22 +256,22 @@ namespace MalachScript::Parser {
{std::string(1, c)});
return Create<LexTokenImpl<LexTokenKind::Unknown>>(TextSpan(start, start + 1));
}
case u8'0':
case u8'1':
case u8'2':
case u8'3':
case u8'4':
case u8'5':
case u8'6':
case u8'7':
case u8'8':
case u8'9': return LexNumerical(c);
case u8'\'': return LexString(u8'\'', false);
case u8'"': {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': return LexNumerical(c);
case '\'': return LexString('\'', false);
case '"': {
if (Peek() == '"' && Peek(2) == '\"') {
return LexString(u8'"', true);
return LexString('"', true);
}
return LexString(u8'"', false);
return LexString('"', false);
}
default:
@ -285,7 +283,7 @@ namespace MalachScript::Parser {
}
}
LexToken* Lexer::LexNumerical(char8_t c) {
LexToken* Lexer::LexNumerical(char c) {
auto initialValue = LexDecimalValue(c);
auto numericalSystem = 10; // Default to decimal system.
if (initialValue == 0) {
@ -361,12 +359,12 @@ namespace MalachScript::Parser {
while (true) {
auto v = (ParseInt)LexDecimalValue(Peek());
if (v == 255) {
if (!isDecimal && Peek() == u8'.') {
if (!isDecimal && Peek() == '.') {
isDecimal = true;
Progress();
continue;
}
if (isDecimal && (Peek() == u8'e' || Peek() == u8'E')) {
if (isDecimal && (Peek() == 'e' || Peek() == 'E')) {
isDecimal = false;
isExponent = true;
Progress();
@ -439,7 +437,7 @@ namespace MalachScript::Parser {
}
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;
Progress();
if (heredoc) {
@ -456,12 +454,12 @@ namespace MalachScript::Parser {
} else if (current == opening) {
break;
}
if (current == u8'\0') {
if (current == '\0') {
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset),
{"EndOfFile"});
break;
}
if (!heredoc && (current == u8'\n' || current == u8'\r')) {
if (!heredoc && (current == '\n' || current == '\r')) {
LogError(Diagnostics::DiagnosticType::ExpectedEndOfString, TextSpan(start, start + offset),
{"Newline"});
break;
@ -486,139 +484,139 @@ namespace MalachScript::Parser {
Progress(offset - 1);
auto hash = Identifier::Hash(str);
switch (hash) {
case Identifier::Hash(u8"and"):
case Identifier::Hash("and"):
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));
case Identifier::Hash(u8"auto"):
case Identifier::Hash("auto"):
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));
case Identifier::Hash(u8"break"):
case Identifier::Hash("break"):
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));
case Identifier::Hash(u8"cast"):
case Identifier::Hash("cast"):
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));
case Identifier::Hash(u8"class"):
case Identifier::Hash("class"):
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));
case Identifier::Hash(u8"continue"):
case Identifier::Hash("continue"):
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));
case Identifier::Hash(u8"do"):
case Identifier::Hash("do"):
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));
case Identifier::Hash(u8"else"):
case Identifier::Hash("else"):
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));
case Identifier::Hash(u8"explicit"):
case Identifier::Hash("explicit"):
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));
case Identifier::Hash(u8"false"):
case Identifier::Hash("false"):
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));
case Identifier::Hash(u8"float"):
case Identifier::Hash("float"):
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));
case Identifier::Hash(u8"from"):
case Identifier::Hash("from"):
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));
case Identifier::Hash(u8"function"):
case Identifier::Hash("function"):
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));
case Identifier::Hash(u8"if"):
case Identifier::Hash("if"):
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));
case Identifier::Hash(u8"in"):
case Identifier::Hash("in"):
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));
case Identifier::Hash(u8"int"):
case Identifier::Hash("int"):
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));
case Identifier::Hash(u8"int8"):
case Identifier::Hash("int8"):
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));
case Identifier::Hash(u8"int32"):
case Identifier::Hash("int32"):
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));
case Identifier::Hash(u8"is"):
case Identifier::Hash("is"):
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));
case Identifier::Hash(u8"namespace"):
case Identifier::Hash("namespace"):
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));
case Identifier::Hash(u8"null"):
case Identifier::Hash("null"):
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));
case Identifier::Hash(u8"out"):
case Identifier::Hash("out"):
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));
case Identifier::Hash(u8"private"):
case Identifier::Hash("private"):
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));
case Identifier::Hash(u8"protected"):
case Identifier::Hash("protected"):
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));
case Identifier::Hash(u8"set"):
case Identifier::Hash("set"):
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));
case Identifier::Hash(u8"super"):
case Identifier::Hash("super"):
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));
case Identifier::Hash(u8"this"):
case Identifier::Hash("this"):
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));
case Identifier::Hash(u8"try"):
case Identifier::Hash("try"):
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));
case Identifier::Hash(u8"uint"):
case Identifier::Hash("uint"):
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));
case Identifier::Hash(u8"uint16"):
case Identifier::Hash("uint16"):
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));
case Identifier::Hash(u8"uint64"):
case Identifier::Hash("uint64"):
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));
case Identifier::Hash(u8"while"):
case Identifier::Hash("while"):
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));
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') {
return true;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
namespace MalachScript::Parser {
class Parser {
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);
private:
@ -110,7 +110,8 @@ namespace MalachScript::Parser {
static bool ParsePrimType(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 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&);
// InitList
inline static bool ParsePreOp(PreOperator& op, const LexToken*& token, const log_func&) {

View File

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

View File

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

View File

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

View File

@ -193,6 +193,7 @@ namespace MalachScript::Parser {
case ParsedStatementKind::Try: break;
case ParsedStatementKind::Switch: 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) \
TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \
auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \
CHECK(token->GetKind() == LexTokenKind::symbol); \
@ -79,10 +79,8 @@ KEYWORD_TEST("while", WhileKeyword);
KEYWORD_TEST("xor", XorKeyword);
namespace doctest {
template <> struct StringMaker<std::u8string> {
static String convert(const std::u8string& value) {
return String(reinterpret_cast<const char*>(value.data()));
}
template <> struct StringMaker<std::string> {
static String convert(const std::string& value) { return String(reinterpret_cast<const char*>(value.data())); }
};
template <> struct StringMaker<LexTokenKind> {
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) \
TEST_CASE("Lex identifier " identifier) { \
MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##identifier, u8##identifier, &diag); \
auto lexer = Lexer(identifier, identifier, &diag); \
const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \
REQUIRE(token->GetKind() == LexTokenKind::Identifier); \
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); \
}

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ using namespace MalachScript::Parser;
#define SYMBOL_TEST(script, symbol) \
TEST_CASE("Lex " script) { \
MalachScript::Diagnostics::Logger diag; \
auto lexer = Lexer(u8##script, u8##script, &diag); \
auto lexer = Lexer(script, script, &diag); \
const auto* token = lexer.Lex(); \
CHECK(diag.GetMessages().empty()); \
CHECK(token->GetKind() == LexTokenKind::symbol); \
@ -71,10 +71,10 @@ SYMBOL_TEST(" ", Whitespace)
#undef SYMBOL_TEST
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) {
MalachScript::Diagnostics::Logger diag;
auto lexer = Lexer(u8"whitespace", v, &diag);
auto lexer = Lexer("whitespace", v, &diag);
const auto* token = lexer.Lex();
CHECK(diag.GetMessages().empty());
CHECK(token->GetKind() == LexTokenKind::Whitespace);

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \
} \
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()); \
asserts; \
delete vec[0]; \
@ -24,7 +24,7 @@ using namespace MalachScript;
PARSER_TEST("Parse basic class without body",
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))),
{
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_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(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::SemicolonSymbol>(TextSpan(0, 0))),
{
@ -45,7 +45,7 @@ PARSER_TEST("Parse basic class without body with whitespaces",
PARSER_TEST(
"Parse basic class with empty body",
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::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))),
{

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \
} \
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()); \
asserts; \
delete vec[0]; \
@ -25,7 +25,7 @@ using namespace MalachScript;
PARSER_TEST("Parse ``void foobar();``",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::VoidKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
@ -41,9 +41,9 @@ PARSER_TEST("Parse ``void foobar();``",
CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"void");
CHECK(id.GetIdentifier().GetString() == "void");
CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar");
CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().empty());
CHECK_FALSE(funcStat->IsConst());
@ -52,13 +52,13 @@ PARSER_TEST("Parse ``void foobar();``",
})
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::IdentifierToken(TextSpan(0, 0), u8"bar"),
new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
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::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::CloseParenthesisSymbol>(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->IsHandle());
auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz");
CHECK(id.GetScope()[1].GetString() == u8"bar");
CHECK(id.GetScope()[0].GetString() == u8"foo");
CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar");
CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
CHECK(paramList->GetParameters().empty());
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_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::IdentifierToken(TextSpan(0, 0), u8"bar"),
new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
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::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::IntKeyword>(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::BoolKeyword>(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::SemicolonSymbol>(TextSpan(0, 0))),
@ -120,11 +120,11 @@ PARSER_TEST("Parse scoped function with parameters without body.",
CHECK_FALSE(type->IsArray());
CHECK_FALSE(type->IsHandle());
auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz");
CHECK(id.GetScope()[1].GetString() == u8"bar");
CHECK(id.GetScope()[0].GetString() == u8"foo");
CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar");
CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
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()->IsHandle());
auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier();
CHECK(par1TypeId.GetIdentifier().GetString() == u8"int");
CHECK(par1TypeId.GetIdentifier().GetString() == "int");
CHECK(par1.GetTypeMod() == TypeMod::None);
CHECK(par1.GetIdentifier().GetString() == u8"par1");
CHECK(par1.GetIdentifier().GetString() == "par1");
CHECK(par1.GetDefaultExpression() == nullptr);
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()->IsHandle());
auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier();
CHECK(par2TypeId.GetIdentifier().GetString() == u8"bool");
CHECK(par2TypeId.GetIdentifier().GetString() == "bool");
CHECK(par2.GetTypeMod() == TypeMod::None);
CHECK(par2.GetIdentifier().GetString() == u8"par2");
CHECK(par2.GetIdentifier().GetString() == "par2");
CHECK(par2.GetDefaultExpression() == nullptr);
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_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::IdentifierToken(TextSpan(0, 0), u8"bar"),
new Parser::IdentifierToken(TextSpan(0, 0), "bar"),
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::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::IntKeyword>(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::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)),
@ -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::OutKeyword>(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::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->IsHandle());
auto& id = type->GetScopedIdentifier();
CHECK(id.GetIdentifier().GetString() == u8"baz");
CHECK(id.GetScope()[1].GetString() == u8"bar");
CHECK(id.GetScope()[0].GetString() == u8"foo");
CHECK(id.GetIdentifier().GetString() == "baz");
CHECK(id.GetScope()[1].GetString() == "bar");
CHECK(id.GetScope()[0].GetString() == "foo");
CHECK_FALSE(funcStat->ReturnsReference());
CHECK(funcStat->GetIdentifier().GetString() == u8"foobar");
CHECK(funcStat->GetIdentifier().GetString() == "foobar");
auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get();
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()->IsHandle());
auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier();
CHECK(par1TypeId.GetIdentifier().GetString() == u8"int");
CHECK(par1TypeId.GetIdentifier().GetString() == "int");
CHECK(par1.GetTypeMod() == TypeMod::RefIn);
CHECK(par1.GetIdentifier().GetString() == u8"par1");
CHECK(par1.GetIdentifier().GetString() == "par1");
CHECK(par1.GetDefaultExpression() == nullptr);
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()->IsHandle());
auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier();
CHECK(par2TypeId.GetIdentifier().GetString() == u8"bool");
CHECK(par2TypeId.GetIdentifier().GetString() == "bool");
CHECK(par2.GetTypeMod() == TypeMod::RefOut);
CHECK(par2.GetIdentifier().GetString() == u8"par2");
CHECK(par2.GetIdentifier().GetString() == "par2");
CHECK(par2.GetDefaultExpression() == nullptr);
CHECK_FALSE(funcStat->IsConst());

View File

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

View File

@ -13,7 +13,7 @@ using namespace MalachScript;
vec[i]->SetNext(vec[i + 1]); \
} \
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()); \
asserts; \
delete vec[0]; \
@ -25,10 +25,10 @@ using namespace MalachScript;
PARSER_TEST(
"Parse class foobar { bool foo { get; set; } }",
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::IdentifierToken(TextSpan(0, 0), u8"bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0)),
@ -46,7 +46,7 @@ PARSER_TEST(
auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo");
REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet());
REQUIRE_FALSE(virtPropStatement->IsGetConst());
@ -58,10 +58,10 @@ PARSER_TEST(
PARSER_TEST(
"Parse class foobar { bool foo { get const; set const; } }",
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::IdentifierToken(TextSpan(0, 0), u8"bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)),
@ -81,7 +81,7 @@ PARSER_TEST(
auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo");
REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet());
REQUIRE(virtPropStatement->IsGetConst());
@ -93,10 +93,10 @@ PARSER_TEST(
PARSER_TEST(
"Parse class foobar { bool foo { get const override; set const override; } }",
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::IdentifierToken(TextSpan(0, 0), u8"bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
new Parser::IdentifierToken(TextSpan(0, 0), "bool"),
new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::ConstKeyword>(TextSpan(0, 0)),
@ -118,7 +118,7 @@ PARSER_TEST(
auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo");
REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet());
REQUIRE(virtPropStatement->IsGetConst());
@ -145,15 +145,14 @@ PARSER_TEST(
PARSER_TEST(
"Virtprops with bodies",
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
PARSER_TEST_TOKENS(
new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), "foobar"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::IdentifierToken(TextSpan(0, 0), u8"int"),
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::IdentifierToken(TextSpan(0, 0), u8"bool"),
new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
new Parser::IdentifierToken(TextSpan(0, 0), "bool"), new Parser::IdentifierToken(TextSpan(0, 0), "foo"),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::GetKeyword>(TextSpan(0, 0)),
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
@ -177,10 +176,10 @@ PARSER_TEST(
new Parser::LexTokenImpl<Parser::LexTokenKind::EqualsEqualsSymbol>(TextSpan(0, 0)),
new Parser::IntegerLiteral(TextSpan(0, 0), 1),
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::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::SemicolonSymbol>(TextSpan(0, 0)),
@ -197,7 +196,7 @@ PARSER_TEST(
auto virtPropStatement =
dynamic_cast<const MalachScript::Parser::ParsedVirtPropStatement*>(firstClassStatement);
REQUIRE(virtPropStatement->GetAccess() == MalachScript::AccessModifier::Public);
REQUIRE(virtPropStatement->GetIdentifier().GetString() == u8"foo");
REQUIRE(virtPropStatement->GetIdentifier().GetString() == "foo");
REQUIRE(virtPropStatement->HasGet());
REQUIRE(virtPropStatement->HasSet());
REQUIRE_FALSE(virtPropStatement->IsGetConst());