Implements very simple REPL, fixes several issues found with it.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
de15173b0b
commit
9109b7513a
@ -12,6 +12,7 @@ endif ()
|
|||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
option(TESTS "Whether the test executable should be build as well." OFF)
|
option(TESTS "Whether the test executable should be build as well." OFF)
|
||||||
|
option(REPL "Whether the repl should be build as well." OFF)
|
||||||
option(STATICC "Whether gcc and stdc++ should be linked statically to the library." OFF)
|
option(STATICC "Whether gcc and stdc++ should be linked statically to the library." OFF)
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
@ -37,5 +38,11 @@ if (TESTS)
|
|||||||
target_compile_definitions(MalachScriptTests PRIVATE TESTS_BUILD)
|
target_compile_definitions(MalachScriptTests PRIVATE TESTS_BUILD)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (REPL)
|
||||||
|
# Create Test executable
|
||||||
|
file(GLOB_RECURSE REPL_FILES "repl/*.cpp" "repl/*.hpp")
|
||||||
|
add_executable(MalachScriptREPL ${REPL_FILES})
|
||||||
|
target_link_libraries(MalachScriptREPL PUBLIC MalachScript curses)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
180
repl/main.cpp
Normal file
180
repl/main.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include "../src/Parser/Lexer/Lexer.hpp"
|
||||||
|
#include "../src/Parser/Parser.hpp"
|
||||||
|
|
||||||
|
void ParseAndUpdate(const std::vector<std::u8string> lines, WINDOW* diagnosticsWindow, WINDOW* parsedWindow) {
|
||||||
|
std::u8string script;
|
||||||
|
for (const auto& line : lines) {
|
||||||
|
script += line;
|
||||||
|
script += '\n';
|
||||||
|
}
|
||||||
|
auto logger = MalachScript::Diagnostics::Logger();
|
||||||
|
auto lexer = MalachScript::Parser::Lexer(u8"diag", script, &logger);
|
||||||
|
const auto* firstToken = lexer.Lex();
|
||||||
|
[[maybe_unused]] const auto* parsedResult = MalachScript::Parser::Parser::Parse(firstToken, u8"diag", &logger);
|
||||||
|
wclear(diagnosticsWindow);
|
||||||
|
waddstr(diagnosticsWindow, (char*)script.c_str());
|
||||||
|
|
||||||
|
for (const auto& diag : logger.GetMessages()) {
|
||||||
|
waddch(diagnosticsWindow, '[');
|
||||||
|
waddstr(diagnosticsWindow, "Error");
|
||||||
|
waddch(diagnosticsWindow, ']');
|
||||||
|
waddch(diagnosticsWindow, ' ');
|
||||||
|
waddstr(diagnosticsWindow,
|
||||||
|
MalachScript::Diagnostics::DiagnosticTypeHelper::ToEnglishString(diag.GetType()).c_str());
|
||||||
|
waddstr(diagnosticsWindow, " - ");
|
||||||
|
auto start = diag.GetSpan().GetStart() - 3;
|
||||||
|
if (start < 0)
|
||||||
|
start = 0;
|
||||||
|
if (start > script.size())
|
||||||
|
start = script.size() - 1;
|
||||||
|
auto end = diag.GetSpan().GetEnd() + 3;
|
||||||
|
if (end >= script.size())
|
||||||
|
end = script.size() - 1;
|
||||||
|
|
||||||
|
waddstr(diagnosticsWindow, (char*)script.substr(start, end - start).c_str());
|
||||||
|
waddch(diagnosticsWindow, '\n');
|
||||||
|
}
|
||||||
|
wrefresh(diagnosticsWindow);
|
||||||
|
|
||||||
|
wclear(parsedWindow);
|
||||||
|
if (logger.GetMessages().size() == 0) {
|
||||||
|
std::stringstream ss;
|
||||||
|
parsedResult->Stringify(ss, 0);
|
||||||
|
|
||||||
|
waddstr(parsedWindow, ss.str().c_str());
|
||||||
|
}
|
||||||
|
wrefresh(parsedWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) {
|
||||||
|
initscr();
|
||||||
|
cbreak();
|
||||||
|
noecho();
|
||||||
|
keypad(stdscr, true);
|
||||||
|
set_tabsize(4);
|
||||||
|
|
||||||
|
int maxX;
|
||||||
|
int maxY;
|
||||||
|
getmaxyx(stdscr, maxY, maxX);
|
||||||
|
wresize(stdscr, maxY, maxX);
|
||||||
|
wrefresh(stdscr);
|
||||||
|
|
||||||
|
const int inputFieldSize = 30;
|
||||||
|
|
||||||
|
wborder(stdscr, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
wmove(stdscr, 31, 1);
|
||||||
|
whline(stdscr, ACS_HLINE, maxX - 2);
|
||||||
|
wmove(stdscr, 32, maxX / 2);
|
||||||
|
wvline(stdscr, ACS_VLINE, 25);
|
||||||
|
|
||||||
|
wrefresh(stdscr);
|
||||||
|
|
||||||
|
auto* inputWindow = newwin(inputFieldSize, maxX - 3, 1, 2);
|
||||||
|
keypad(inputWindow, true);
|
||||||
|
|
||||||
|
auto* diagnosticsWindow = newwin(25, (maxX - 4) / 2, 32, 2);
|
||||||
|
|
||||||
|
auto* parsedResultWindow = newwin(25, (maxX - 4) / 2 - 2, 32, (maxX - 4) / 2 + 4);
|
||||||
|
wrefresh(parsedResultWindow);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
int col = 0;
|
||||||
|
|
||||||
|
std::vector<std::u8string> lines = {u8""};
|
||||||
|
|
||||||
|
int c;
|
||||||
|
bool running = true;
|
||||||
|
while (running) {
|
||||||
|
c = wgetch(inputWindow);
|
||||||
|
switch (c) {
|
||||||
|
case 27: running = false; break;
|
||||||
|
|
||||||
|
case KEY_LEFT: {
|
||||||
|
if (col > 0) {
|
||||||
|
wmove(inputWindow, row, --col);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEY_RIGHT: {
|
||||||
|
auto& line = lines[row];
|
||||||
|
if (col < (int)line.size()) {
|
||||||
|
wmove(inputWindow, row, ++col);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEY_UP:
|
||||||
|
if (row > 0) {
|
||||||
|
wmove(inputWindow, --row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrefresh(stdscr);
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (row < (int)lines.size() - 1) {
|
||||||
|
wmove(inputWindow, ++row, col);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_BACKSPACE:
|
||||||
|
case 127:
|
||||||
|
if (col > 0) {
|
||||||
|
mvwdelch(inputWindow, row, --col);
|
||||||
|
auto& line = lines[row];
|
||||||
|
line = line.erase(col, 1);
|
||||||
|
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
case KEY_ENTER:
|
||||||
|
lines.insert(lines.begin() + row + 1, u8"");
|
||||||
|
row++;
|
||||||
|
col = 0;
|
||||||
|
for (size_t i = row - 1; i < lines.size(); i++) {
|
||||||
|
wmove(inputWindow, i, 0);
|
||||||
|
wclrtoeol(inputWindow);
|
||||||
|
waddstr(inputWindow, (char*)lines[i].c_str());
|
||||||
|
}
|
||||||
|
wmove(inputWindow, row, col);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
case KEY_STAB: {
|
||||||
|
wmove(inputWindow, row, 0);
|
||||||
|
wclrtoeol(inputWindow);
|
||||||
|
auto& line = lines[row];
|
||||||
|
if ((int)line.length() <= col) {
|
||||||
|
line += u8" ";
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
line.insert(line.begin() + col, u8' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waddstr(inputWindow, (char*)line.c_str());
|
||||||
|
col += 4;
|
||||||
|
wmove(inputWindow, row, col);
|
||||||
|
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
wmove(inputWindow, row, 0);
|
||||||
|
auto& line = lines[row];
|
||||||
|
if ((int)line.length() <= col) {
|
||||||
|
line += (char8_t)c;
|
||||||
|
} else {
|
||||||
|
line.insert(line.begin() + col, c);
|
||||||
|
}
|
||||||
|
waddstr(inputWindow, (char*)line.c_str());
|
||||||
|
col++;
|
||||||
|
wmove(inputWindow, row, col);
|
||||||
|
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrefresh(inputWindow);
|
||||||
|
}
|
||||||
|
endwin();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -35,21 +35,26 @@ 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 std::u8string empty;
|
static std::u8string empty;
|
||||||
|
|
||||||
class Identifier {
|
class Identifier {
|
||||||
std::u8string_view _str;
|
const char8_t* _str;
|
||||||
|
size_t _length;
|
||||||
uint32_t _hash;
|
uint32_t _hash;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Identifier() : _str(empty), _hash(0) {}
|
Identifier() : _str(nullptr), _length(0), _hash(0) {}
|
||||||
constexpr Identifier(const char8_t* c) : _str(c), _hash(Hash(c)) {}
|
constexpr Identifier(const char8_t* c) : _str(c), _length(CalcLength(c)), _hash(Hash(c)) {}
|
||||||
Identifier(const std::u8string_view& c) : _str(c), _hash(Hash(c)) {}
|
constexpr Identifier(const char8_t* c, size_t length, uint32_t hash) : _str(c), _length(length), _hash(hash) {}
|
||||||
Identifier(const std::u8string_view& c, uint32_t hash) : _str(c), _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 const std::u8string_view& GetString() const noexcept { return _str; }
|
[[nodiscard]] constexpr inline std::u8string_view GetString() const noexcept {
|
||||||
|
return std::u8string_view(_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::u8string_view& sv) {
|
||||||
uint32_t crc = 0xffffffff;
|
uint32_t crc = 0xffffffff;
|
||||||
@ -59,6 +64,11 @@ namespace MalachScript {
|
|||||||
return crc ^ 0xffffffff;
|
return crc ^ 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const Identifier& c) {
|
||||||
|
out << std::string((const char*)c._str, c._length);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace MalachScript::Diagnostics {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DiagnosticTypeHelper {
|
class DiagnosticTypeHelper {
|
||||||
|
public:
|
||||||
static std::string ToEnglishString(DiagnosticType type) {
|
static std::string ToEnglishString(DiagnosticType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DiagnosticType::UnknownToken: return "Unknown token";
|
case DiagnosticType::UnknownToken: return "Unknown token";
|
||||||
|
@ -599,7 +599,7 @@ namespace MalachScript::Parser {
|
|||||||
case Identifier::Hash(u8"xor"):
|
case Identifier::Hash(u8"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, hash));
|
default: return Create<IdentifierToken>(TextSpan(start, _position), Identifier(str.data(), offset, hash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool Lexer::IsAlphaNumericalOrUnderscore(char8_t c) {
|
bool Lexer::IsAlphaNumericalOrUnderscore(char8_t c) {
|
||||||
|
@ -49,6 +49,7 @@ namespace MalachScript::Parser {
|
|||||||
ParseFunc(statement, currentToken, log) || ParseNamespace(statement, currentToken, log);
|
ParseFunc(statement, currentToken, log) || ParseNamespace(statement, currentToken, log);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// TODO: Log error
|
// TODO: Log error
|
||||||
|
logError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -82,6 +83,7 @@ namespace MalachScript::Parser {
|
|||||||
Identifier identifier;
|
Identifier identifier;
|
||||||
if (!ParseIdentifier(identifier, current)) {
|
if (!ParseIdentifier(identifier, current)) {
|
||||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
PROGRESS_TOKEN(current);
|
PROGRESS_TOKEN(current);
|
||||||
std::vector<Identifier> inherits;
|
std::vector<Identifier> inherits;
|
||||||
@ -97,18 +99,21 @@ namespace MalachScript::Parser {
|
|||||||
Identifier id;
|
Identifier id;
|
||||||
if (!ParseIdentifier(id, current)) {
|
if (!ParseIdentifier(id, current)) {
|
||||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
inherits.push_back(id);
|
inherits.push_back(id);
|
||||||
while (current->GetKind() == LexTokenKind::CommaSymbol) {
|
while (current->GetKind() == LexTokenKind::CommaSymbol) {
|
||||||
PROGRESS_TOKEN(current);
|
PROGRESS_TOKEN(current);
|
||||||
if (!ParseIdentifier(id, current)) {
|
if (!ParseIdentifier(id, current)) {
|
||||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
inherits.push_back(id);
|
inherits.push_back(id);
|
||||||
PROGRESS_TOKEN(current);
|
PROGRESS_TOKEN(current);
|
||||||
}
|
}
|
||||||
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
||||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
// Intentionally don't break so we continue into the inner body statement.
|
// Intentionally don't break so we continue into the inner body statement.
|
||||||
@ -132,7 +137,7 @@ namespace MalachScript::Parser {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: throw;
|
default: return false;
|
||||||
}
|
}
|
||||||
out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), classAttr, identifier, inherits,
|
out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), classAttr, identifier, inherits,
|
||||||
body);
|
body);
|
||||||
@ -239,6 +244,7 @@ namespace MalachScript::Parser {
|
|||||||
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||||
if (!ParseStatBlock(statblock, current, log)) {
|
if (!ParseStatBlock(statblock, current, log)) {
|
||||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PROGRESS_TOKEN(current);
|
PROGRESS_TOKEN(current);
|
||||||
@ -367,6 +373,7 @@ namespace MalachScript::Parser {
|
|||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
|
if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
|
||||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
|
||||||
@ -385,9 +392,13 @@ namespace MalachScript::Parser {
|
|||||||
|
|
||||||
if (!ParseType(typeStatement, currentToken, log)) {
|
if (!ParseType(typeStatement, currentToken, log)) {
|
||||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
ParseTypeMod(typeMod, currentToken, log);
|
ParseTypeMod(typeMod, currentToken, log);
|
||||||
ParseIdentifier(identifier, currentToken);
|
if (!ParseIdentifier(identifier, currentToken)) {
|
||||||
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
// TODO: Default expression
|
// TODO: Default expression
|
||||||
|
|
||||||
@ -403,10 +414,12 @@ namespace MalachScript::Parser {
|
|||||||
while (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
|
while (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
|
||||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
if (currentToken->GetKind() == LexTokenKind::EndOfFile) {
|
if (currentToken->GetKind() == LexTokenKind::EndOfFile) {
|
||||||
break;
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (currentToken->GetKind() == LexTokenKind::SemicolonSymbol) {
|
if (currentToken->GetKind() == LexTokenKind::SemicolonSymbol) {
|
||||||
break;
|
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
PROGRESS_TOKEN(currentToken);
|
PROGRESS_TOKEN(currentToken);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
#ifndef MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
||||||
#define MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
#define MALACHSCRIPT_PARSEDSTATEMENT_HPP
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "../../CoreData/AccessModifier.hpp"
|
#include "../../CoreData/AccessModifier.hpp"
|
||||||
@ -18,6 +19,13 @@ namespace MalachScript::Parser {
|
|||||||
virtual ~ParsedStatement() = default;
|
virtual ~ParsedStatement() = default;
|
||||||
[[nodiscard]] virtual ParsedStatementKind GetKind() const noexcept = 0;
|
[[nodiscard]] virtual ParsedStatementKind GetKind() const noexcept = 0;
|
||||||
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
|
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
|
||||||
|
|
||||||
|
virtual void Stringify(std::stringstream& stream, uint8_t indents) const {
|
||||||
|
for (uint8_t i = 0; i < indents; i++) {
|
||||||
|
stream << "\t";
|
||||||
|
}
|
||||||
|
stream << ParsedStatementKindHelper::ToString(GetKind());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <ParsedStatementKind kind> class ParsedStatementImpl : public ParsedStatement {
|
template <ParsedStatementKind kind> class ParsedStatementImpl : public ParsedStatement {
|
||||||
@ -39,6 +47,15 @@ namespace MalachScript::Parser {
|
|||||||
[[nodiscard]] inline const std::vector<std::unique_ptr<const ParsedStatement>>& GetStatements() const noexcept {
|
[[nodiscard]] inline const std::vector<std::unique_ptr<const ParsedStatement>>& GetStatements() const noexcept {
|
||||||
return _statements;
|
return _statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stringify(std::stringstream& stream, uint8_t indents) const override {
|
||||||
|
ParsedStatement::Stringify(stream, indents);
|
||||||
|
stream << std::to_string(GetStatements().size());
|
||||||
|
stream << std::endl;
|
||||||
|
for (const auto& s : GetStatements()) {
|
||||||
|
s->Stringify(stream, indents + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedClassStatement : public ParsedStatementImpl<ParsedStatementKind::Class> {
|
class ParsedClassStatement : public ParsedStatementImpl<ParsedStatementKind::Class> {
|
||||||
@ -58,6 +75,15 @@ namespace MalachScript::Parser {
|
|||||||
return _body;
|
return _body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stringify(std::stringstream& stream, uint8_t indents) const override {
|
||||||
|
ParsedStatement::Stringify(stream, indents);
|
||||||
|
stream << " " << _identifier;
|
||||||
|
stream << std::endl;
|
||||||
|
for (const auto& s : GetBody()) {
|
||||||
|
s->Stringify(stream, indents + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClassAttr _classAttr;
|
ClassAttr _classAttr;
|
||||||
Identifier _identifier;
|
Identifier _identifier;
|
||||||
@ -108,6 +134,23 @@ namespace MalachScript::Parser {
|
|||||||
[[nodiscard]] inline bool IsArray() const noexcept { return _isArray; }
|
[[nodiscard]] inline bool IsArray() const noexcept { return _isArray; }
|
||||||
[[nodiscard]] inline bool IsHandle() const noexcept { return _isHandle; }
|
[[nodiscard]] inline bool IsHandle() const noexcept { return _isHandle; }
|
||||||
[[nodiscard]] inline const ScopedIdentifier& GetScopedIdentifier() const noexcept { return _scopedIdentifier; }
|
[[nodiscard]] inline const ScopedIdentifier& GetScopedIdentifier() const noexcept { return _scopedIdentifier; }
|
||||||
|
|
||||||
|
void Stringify(std::stringstream& stream, uint8_t) const override {
|
||||||
|
if (_isConst) {
|
||||||
|
stream << "const ";
|
||||||
|
}
|
||||||
|
for (auto identifier : _scopedIdentifier.GetScope()) {
|
||||||
|
stream << identifier;
|
||||||
|
stream << "::";
|
||||||
|
}
|
||||||
|
stream << _scopedIdentifier.GetIdentifier();
|
||||||
|
if (_isArray) {
|
||||||
|
stream << "[]";
|
||||||
|
}
|
||||||
|
if (_isHandle) {
|
||||||
|
stream << "&";
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedParamListStatement : public ParsedStatementImpl<ParsedStatementKind::ParamList> {
|
class ParsedParamListStatement : public ParsedStatementImpl<ParsedStatementKind::ParamList> {
|
||||||
@ -160,6 +203,15 @@ namespace MalachScript::Parser {
|
|||||||
[[nodiscard]] const std::vector<std::unique_ptr<const ParsedParameter>>& GetParameters() const noexcept {
|
[[nodiscard]] const std::vector<std::unique_ptr<const ParsedParameter>>& GetParameters() const noexcept {
|
||||||
return _parameters;
|
return _parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stringify(std::stringstream& stream, uint8_t indents) const override {
|
||||||
|
stream << "(";
|
||||||
|
for (auto& param : GetParameters()) {
|
||||||
|
param->GetTypeStatement()->Stringify(stream, indents);
|
||||||
|
stream << " " << param->GetIdentifier();
|
||||||
|
}
|
||||||
|
stream << ")";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedFuncStatement : public ParsedStatementImpl<ParsedStatementKind::Func> {
|
class ParsedFuncStatement : public ParsedStatementImpl<ParsedStatementKind::Func> {
|
||||||
@ -200,6 +252,14 @@ namespace MalachScript::Parser {
|
|||||||
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetStatBlock() const noexcept {
|
[[nodiscard]] inline const std::unique_ptr<const ParsedStatement>& GetStatBlock() const noexcept {
|
||||||
return _statBlock;
|
return _statBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stringify(std::stringstream& stream, uint8_t indents) const override {
|
||||||
|
ParsedStatement::Stringify(stream, indents);
|
||||||
|
stream << " " << _identifier;
|
||||||
|
GetParamList()->Stringify(stream, 0);
|
||||||
|
stream << std::endl;
|
||||||
|
GetStatBlock()->Stringify(stream, indents + 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedVirtPropStatement : public ParsedStatementImpl<ParsedStatementKind::VirtProp> {
|
class ParsedVirtPropStatement : public ParsedStatementImpl<ParsedStatementKind::VirtProp> {
|
||||||
|
@ -31,6 +31,41 @@ namespace MalachScript::Parser {
|
|||||||
Switch,
|
Switch,
|
||||||
Case,
|
Case,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParsedStatementKindHelper {
|
||||||
|
public:
|
||||||
|
static std::string_view ToString(ParsedStatementKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case ParsedStatementKind::Unknown: return "Unknown";
|
||||||
|
case ParsedStatementKind::Script: return "Script";
|
||||||
|
case ParsedStatementKind::Class: return "Class";
|
||||||
|
case ParsedStatementKind::TypeDef: return "TypeDef";
|
||||||
|
case ParsedStatementKind::Namespace: return "Namespace";
|
||||||
|
case ParsedStatementKind::Type: return "Type";
|
||||||
|
case ParsedStatementKind::ParamList: return "ParamList";
|
||||||
|
case ParsedStatementKind::Func: return "Func";
|
||||||
|
case ParsedStatementKind::VirtProp: return "VirtProp";
|
||||||
|
case ParsedStatementKind::StatBlock: return "StatBlock";
|
||||||
|
case ParsedStatementKind::If: return "If";
|
||||||
|
case ParsedStatementKind::Assign: return "Assign";
|
||||||
|
case ParsedStatementKind::BinaryExpression: return "BinaryExpression";
|
||||||
|
case ParsedStatementKind::Void: return "Void";
|
||||||
|
case ParsedStatementKind::Literal: return "Literal";
|
||||||
|
case ParsedStatementKind::Return: return "Return";
|
||||||
|
case ParsedStatementKind::VarAccess: return "VarAccess";
|
||||||
|
case ParsedStatementKind::Increment: return "Increment";
|
||||||
|
case ParsedStatementKind::Decrement: return "Decrement";
|
||||||
|
case ParsedStatementKind::Continue: return "Continue";
|
||||||
|
case ParsedStatementKind::Break: return "Break";
|
||||||
|
case ParsedStatementKind::For: return "For";
|
||||||
|
case ParsedStatementKind::While: return "While";
|
||||||
|
case ParsedStatementKind::DoWhile: return "DoWhile";
|
||||||
|
case ParsedStatementKind::Try: return "Try";
|
||||||
|
case ParsedStatementKind::Switch: return "Switch";
|
||||||
|
case ParsedStatementKind::Case: return "Case";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MALACHSCRIPT_PARSEDSTATEMENTKIND_HPP
|
#endif // MALACHSCRIPT_PARSEDSTATEMENTKIND_HPP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user