Initial work on more detailed error messages.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
7d0c5cbbed
commit
d907a58f64
|
@ -0,0 +1,151 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace util {
|
||||
class ArgBase {
|
||||
public:
|
||||
ArgBase() {}
|
||||
virtual ~ArgBase() {}
|
||||
virtual void Format(std::ostringstream& ss, const std::string& fmt) = 0;
|
||||
};
|
||||
|
||||
template <class T> class Arg : public ArgBase {
|
||||
public:
|
||||
Arg(T arg) : m_arg(arg) {}
|
||||
virtual ~Arg() {}
|
||||
virtual void Format(std::ostringstream& ss, const std::string&) { ss << m_arg; }
|
||||
|
||||
private:
|
||||
T m_arg;
|
||||
};
|
||||
|
||||
class ArgArray : public std::vector<ArgBase*> {
|
||||
public:
|
||||
ArgArray() {}
|
||||
~ArgArray() {
|
||||
std::for_each(begin(), end(), [](ArgBase* p) { delete p; });
|
||||
}
|
||||
};
|
||||
|
||||
static void FormatItem(std::ostringstream& ss, const std::string& item, const ArgArray& args) {
|
||||
int index = 0;
|
||||
int alignment = 0;
|
||||
std::string fmt;
|
||||
|
||||
char* endptr = nullptr;
|
||||
index = strtol(&item[0], &endptr, 10);
|
||||
if (index < 0 || index >= (int)args.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*endptr == ',') {
|
||||
alignment = strtol(endptr + 1, &endptr, 10);
|
||||
if (alignment > 0) {
|
||||
ss << std::right << std::setw(alignment);
|
||||
} else if (alignment < 0) {
|
||||
ss << std::left << std::setw(-alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (*endptr == ':') {
|
||||
fmt = endptr + 1;
|
||||
}
|
||||
|
||||
args[index]->Format(ss, fmt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T> static void Transfer(ArgArray& argArray, T t) { argArray.push_back(new Arg<T>(t)); }
|
||||
|
||||
template <class T, typename... Args> static void Transfer(ArgArray& argArray, T t, Args&&... args) {
|
||||
Transfer(argArray, t);
|
||||
Transfer(argArray, args...);
|
||||
}
|
||||
|
||||
template <typename... Args> std::string Format(const std::string& format, Args&&... args) {
|
||||
if (sizeof...(args) == 0) {
|
||||
return format;
|
||||
}
|
||||
|
||||
ArgArray argArray;
|
||||
Transfer(argArray, args...);
|
||||
size_t start = 0;
|
||||
size_t pos = 0;
|
||||
std::ostringstream ss;
|
||||
while (true) {
|
||||
pos = format.find('{', start);
|
||||
if (pos == std::string::npos) {
|
||||
ss << format.substr(start);
|
||||
break;
|
||||
}
|
||||
|
||||
ss << format.substr(start, pos - start);
|
||||
if (format[pos + 1] == '{') {
|
||||
ss << '{';
|
||||
start = pos + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
start = pos + 1;
|
||||
pos = format.find('}', start);
|
||||
if (pos == std::string::npos) {
|
||||
ss << format.substr(start - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
FormatItem(ss, format.substr(start, pos - start), argArray);
|
||||
start = pos + 1;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string Format(const std::string& format, const std::vector<std::string>& args) {
|
||||
if (args.size() == 0) {
|
||||
return format;
|
||||
}
|
||||
|
||||
ArgArray argArray;
|
||||
for (const auto& arg : args) {
|
||||
Transfer(argArray, arg);
|
||||
}
|
||||
size_t start = 0;
|
||||
size_t pos = 0;
|
||||
std::ostringstream ss;
|
||||
while (true) {
|
||||
pos = format.find('{', start);
|
||||
if (pos == std::string::npos) {
|
||||
ss << format.substr(start);
|
||||
break;
|
||||
}
|
||||
|
||||
ss << format.substr(start, pos - start);
|
||||
if (format[pos + 1] == '{') {
|
||||
ss << '{';
|
||||
start = pos + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
start = pos + 1;
|
||||
pos = format.find('}', start);
|
||||
if (pos == std::string::npos) {
|
||||
ss << format.substr(start - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
FormatItem(ss, format.substr(start, pos - start), argArray);
|
||||
start = pos + 1;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <fstream>
|
||||
#include <ncurses.h>
|
||||
#include <sstream>
|
||||
#include "../src/Diagnostics/DiagnosticTypeEN_US.hpp"
|
||||
#include "../src/Parser/Lexer/Lexer.hpp"
|
||||
#include "../src/Parser/Parser.hpp"
|
||||
#include "../src/Parser/Statements/ParsedStatementStringifier.hpp"
|
||||
|
@ -43,8 +44,7 @@ void ParseAndUpdate(const std::vector<std::u8string>& lines, WINDOW* diagnostics
|
|||
waddstr(diagnosticsWindow, std::to_string(diag->GetSpan().GetEnd() + 1).c_str());
|
||||
waddch(diagnosticsWindow, ' ');
|
||||
|
||||
waddstr(diagnosticsWindow,
|
||||
MalachScript::Diagnostics::DiagnosticTypeHelper::ToEnglishString(diag->GetType()).c_str());
|
||||
waddstr(diagnosticsWindow, MalachScript::Diagnostics::DiagnosticTypeHelper::ToEnglishString(diag).c_str());
|
||||
|
||||
waddch(diagnosticsWindow, '\n');
|
||||
}
|
||||
|
|
|
@ -11,16 +11,18 @@ namespace MalachScript::Diagnostics {
|
|||
DiagnosticType _type;
|
||||
std::u8string_view _scriptName;
|
||||
TextSpan _span;
|
||||
std::vector<std::string> _formats;
|
||||
|
||||
public:
|
||||
inline Diagnostic(DiagnosticLevel level, DiagnosticType type, const std::u8string_view& scriptName,
|
||||
TextSpan span)
|
||||
: _level(level), _type(type), _scriptName(scriptName), _span(span) {}
|
||||
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::vector<std::string>& GetFormats() const noexcept { return _formats; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,20 +10,6 @@ namespace MalachScript::Diagnostics {
|
|||
UnexpectedToken,
|
||||
DoubleProperty,
|
||||
};
|
||||
|
||||
class DiagnosticTypeHelper {
|
||||
public:
|
||||
static std::string ToEnglishString(DiagnosticType type) {
|
||||
switch (type) {
|
||||
case DiagnosticType::UnknownToken: return "Unknown token";
|
||||
case DiagnosticType::InvalidNumericalBase: return "Invalid numerical base";
|
||||
case DiagnosticType::ExpectedEndOfString: return "Expected end of string";
|
||||
case DiagnosticType::UnexpectedToken: return "Unexpected Token";
|
||||
case DiagnosticType::DoubleProperty: return "Property block found twice.";
|
||||
}
|
||||
return std::to_string((uint8_t)type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MALACHSCRIPT_DIAGNOSTICTYPE_HPP
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MALACHSCRIPT_DIAGNOSTICTYPEEN_US_HPP
|
||||
#define MALACHSCRIPT_DIAGNOSTICTYPEEN_US_HPP
|
||||
|
||||
#include "../../extern/format.hpp"
|
||||
#include "Diagnostic.hpp"
|
||||
|
||||
namespace MalachScript::Diagnostics {
|
||||
class DiagnosticTypeHelper {
|
||||
public:
|
||||
static std::string ToEnglishString(const Diagnostic* diag) {
|
||||
switch (diag->GetType()) {
|
||||
case DiagnosticType::UnknownToken: return "Unknown token";
|
||||
case DiagnosticType::InvalidNumericalBase: return "Invalid numerical base";
|
||||
case DiagnosticType::ExpectedEndOfString: return "Expected end of string";
|
||||
case DiagnosticType::UnexpectedToken:
|
||||
return util::Format("Unexpected Token. Expected any of: {0}, but found {1}", diag->GetFormats());
|
||||
case DiagnosticType::DoubleProperty: return "Property block found twice.";
|
||||
}
|
||||
return std::to_string((uint8_t)diag->GetType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MALACHSCRIPT_DIAGNOSTICTYPEEN_US_HPP
|
|
@ -9,8 +9,9 @@ namespace MalachScript::Diagnostics {
|
|||
std::vector<Diagnostic> _messages;
|
||||
|
||||
public:
|
||||
inline void Log(DiagnosticLevel level, DiagnosticType type, std::u8string_view scriptName, TextSpan span) {
|
||||
_messages.emplace_back(level, type, scriptName, span);
|
||||
inline void Log(DiagnosticLevel level, DiagnosticType type, std::u8string_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) {
|
||||
Log(DiagnosticLevel::Trace, type, scriptName, span);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define MALACHSCRIPT_LEXTOKEN_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include "../../CoreData/Identifier.hpp"
|
||||
#include "../../TextSpan.hpp"
|
||||
#include "../ParserDefines.hpp"
|
||||
|
@ -18,6 +19,7 @@ namespace MalachScript::Parser {
|
|||
[[nodiscard]] virtual LexTokenKind GetKind() const noexcept = 0;
|
||||
[[nodiscard]] inline const std::unique_ptr<const LexToken>& GetNext() const noexcept { return _next; }
|
||||
[[nodiscard]] inline const TextSpan& GetSpan() const noexcept { return _span; }
|
||||
[[nodiscard]] virtual std::string ToString() const noexcept { return LexTokenKindHelper::ToString(GetKind()); }
|
||||
|
||||
inline void SetNext(LexToken* token) { _next = std::unique_ptr<const LexToken>(token); }
|
||||
};
|
||||
|
@ -35,6 +37,12 @@ namespace MalachScript::Parser {
|
|||
IntegerLiteral(const TextSpan& span, ParseInt value)
|
||||
: LexTokenImpl<LexTokenKind::IntegerLiteral>(span), _value(value) {}
|
||||
[[nodiscard]] inline ParseInt GetValue() const noexcept { return _value; }
|
||||
|
||||
[[nodiscard]] std::string ToString() const noexcept override {
|
||||
std::stringstream ss;
|
||||
ss << "Integer(" << GetValue() << ")";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class FloatLiteral : public LexTokenImpl<LexTokenKind::FloatLiteral> {
|
||||
|
@ -44,6 +52,12 @@ namespace MalachScript::Parser {
|
|||
FloatLiteral(const TextSpan& span, ParseFloat value)
|
||||
: LexTokenImpl<LexTokenKind::FloatLiteral>(span), _value(value) {}
|
||||
[[nodiscard]] inline long double GetValue() const noexcept { return _value; }
|
||||
|
||||
std::string ToString() const noexcept override {
|
||||
std::stringstream ss;
|
||||
ss << "Float(" << GetValue() << ")";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class StringLiteral : public LexTokenImpl<LexTokenKind::StringLiteral> {
|
||||
|
@ -53,6 +67,14 @@ namespace MalachScript::Parser {
|
|||
StringLiteral(const TextSpan& span, ParseString value)
|
||||
: LexTokenImpl<LexTokenKind::StringLiteral>(span), _value(std::move(value)) {}
|
||||
[[nodiscard]] inline const ParseString& GetValue() const noexcept { return _value; }
|
||||
|
||||
std::string ToString() const noexcept override {
|
||||
std::stringstream ss;
|
||||
ss << "String("
|
||||
<< "\"" << (char*)GetValue().c_str() << "\""
|
||||
<< ")";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class IdentifierToken : public LexTokenImpl<LexTokenKind::Identifier> {
|
||||
|
@ -62,6 +84,12 @@ namespace MalachScript::Parser {
|
|||
IdentifierToken(const TextSpan& span, Identifier value)
|
||||
: LexTokenImpl<LexTokenKind::Identifier>(span), _value(value) {}
|
||||
[[nodiscard]] inline const Identifier& GetValue() const noexcept { return _value; }
|
||||
|
||||
[[nodiscard]] std::string ToString() const noexcept override {
|
||||
std::stringstream ss;
|
||||
ss << "Identifier(" << GetValue() << ")";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "LexTokenKind.hpp"
|
||||
#include <ostream>
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, MalachScript::Parser::LexTokenKind kind) {
|
||||
os << MalachScript::Parser::LexTokenKindHelper::ToString(kind);
|
||||
return os;
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
#define MALACHSCRIPT_LEXTOKENKIND_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace MalachScript::Parser {
|
||||
enum class LexTokenKind : uint8_t {
|
||||
Unknown,
|
||||
|
@ -134,6 +136,139 @@ namespace MalachScript::Parser {
|
|||
StringLiteral,
|
||||
Identifier,
|
||||
};
|
||||
|
||||
class LexTokenKindHelper {
|
||||
public:
|
||||
static std::string ToString(LexTokenKind kind) {
|
||||
switch (kind) {
|
||||
|
||||
case LexTokenKind::Unknown: return "Unknown";
|
||||
case LexTokenKind::EndOfFile: return "EndOfFile";
|
||||
case LexTokenKind::Whitespace: break;
|
||||
case LexTokenKind::StarSymbol: break;
|
||||
case LexTokenKind::StarStarSymbol: break;
|
||||
case LexTokenKind::SlashSymbol: break;
|
||||
case LexTokenKind::PercentSymbol: break;
|
||||
case LexTokenKind::PlusSymbol: break;
|
||||
case LexTokenKind::MinusSymbol: break;
|
||||
case LexTokenKind::LessThanEqualsSymbol: break;
|
||||
case LexTokenKind::LessThanSymbol: break;
|
||||
case LexTokenKind::GreaterThanEqualsSymbol: break;
|
||||
case LexTokenKind::GreaterThanSymbol: break;
|
||||
case LexTokenKind::OpenParenthesisSymbol: break;
|
||||
case LexTokenKind::CloseParenthesisSymbol: break;
|
||||
case LexTokenKind::EqualsEqualsSymbol: break;
|
||||
case LexTokenKind::ExclamationMarkEqualsSymbol: break;
|
||||
case LexTokenKind::QuestionMarkSymbol: break;
|
||||
case LexTokenKind::ColonSymbol: break;
|
||||
case LexTokenKind::EqualsSymbol: break;
|
||||
case LexTokenKind::PlusEqualsSymbol: break;
|
||||
case LexTokenKind::MinusEqualsSymbol: break;
|
||||
case LexTokenKind::StarEqualsSymbol: break;
|
||||
case LexTokenKind::SlashEqualsSymbol: break;
|
||||
case LexTokenKind::PercentEqualsSymbol: break;
|
||||
case LexTokenKind::StarStarEqualsSymbol: break;
|
||||
case LexTokenKind::PlusPlusSymbol: break;
|
||||
case LexTokenKind::MinusMinusSymbol: break;
|
||||
case LexTokenKind::AmpersandSymbol: break;
|
||||
case LexTokenKind::CommaSymbol: break;
|
||||
case LexTokenKind::OpenCurlyParenthesisSymbol: break;
|
||||
case LexTokenKind::CloseCurlyParenthesisSymbol: break;
|
||||
case LexTokenKind::SemicolonSymbol: break;
|
||||
case LexTokenKind::VerticalLineSymbol: break;
|
||||
case LexTokenKind::CaretSymbol: break;
|
||||
case LexTokenKind::TildeSymbol: break;
|
||||
case LexTokenKind::LessThanLessThanSymbol: break;
|
||||
case LexTokenKind::GreaterThanGreaterThanSymbol: break;
|
||||
case LexTokenKind::GreaterThanGreaterThanGreaterThanSymbol: break;
|
||||
case LexTokenKind::AmpersandEqualsSymbol: break;
|
||||
case LexTokenKind::VerticalLineEqualsSymbol: break;
|
||||
case LexTokenKind::CaretEqualsSymbol: break;
|
||||
case LexTokenKind::LessThanLessThanEqualsSymbol: break;
|
||||
case LexTokenKind::GreaterThanGreaterThanEqualsSymbol: break;
|
||||
case LexTokenKind::GreaterThanGreaterThanGreaterThanEqualsSymbol: break;
|
||||
case LexTokenKind::DotSymbol: break;
|
||||
case LexTokenKind::AmpersandAmpersandSymbol: break;
|
||||
case LexTokenKind::VerticalLineVerticalLineSymbol: break;
|
||||
case LexTokenKind::ExclamationMarkSymbol: break;
|
||||
case LexTokenKind::OpenBlockParenthesisSymbol: break;
|
||||
case LexTokenKind::CloseBlockParenthesisSymbol: break;
|
||||
case LexTokenKind::CaretCaretSymbol: break;
|
||||
case LexTokenKind::AtSymbol: break;
|
||||
case LexTokenKind::ExclamationMarkIsSymbol: break;
|
||||
case LexTokenKind::ColonColonSymbol: break;
|
||||
case LexTokenKind::AndKeyword: break;
|
||||
case LexTokenKind::AbstractKeyword: break;
|
||||
case LexTokenKind::AutoKeyword: break;
|
||||
case LexTokenKind::BoolKeyword: break;
|
||||
case LexTokenKind::BreakKeyword: break;
|
||||
case LexTokenKind::CaseKeyword: break;
|
||||
case LexTokenKind::CastKeyword: break;
|
||||
case LexTokenKind::CatchKeyword: break;
|
||||
case LexTokenKind::ClassKeyword: break;
|
||||
case LexTokenKind::ConstKeyword: break;
|
||||
case LexTokenKind::ContinueKeyword: break;
|
||||
case LexTokenKind::DefaultKeyword: break;
|
||||
case LexTokenKind::DoKeyword: break;
|
||||
case LexTokenKind::DoubleKeyword: break;
|
||||
case LexTokenKind::ElseKeyword: break;
|
||||
case LexTokenKind::EnumKeyword: break;
|
||||
case LexTokenKind::ExplicitKeyword: break;
|
||||
case LexTokenKind::ExternalKeyword: break;
|
||||
case LexTokenKind::FalseKeyword: break;
|
||||
case LexTokenKind::FinalKeyword: break;
|
||||
case LexTokenKind::FloatKeyword: break;
|
||||
case LexTokenKind::ForKeyword: break;
|
||||
case LexTokenKind::FromKeyword: break;
|
||||
case LexTokenKind::FuncdefKeyword: break;
|
||||
case LexTokenKind::FunctionKeyword: break;
|
||||
case LexTokenKind::GetKeyword: break;
|
||||
case LexTokenKind::IfKeyword: break;
|
||||
case LexTokenKind::ImportKeyword: break;
|
||||
case LexTokenKind::InKeyword: break;
|
||||
case LexTokenKind::InoutKeyword: break;
|
||||
case LexTokenKind::IntKeyword: break;
|
||||
case LexTokenKind::InterfaceKeyword: break;
|
||||
case LexTokenKind::Int8Keyword: break;
|
||||
case LexTokenKind::Int16Keyword: break;
|
||||
case LexTokenKind::Int32Keyword: break;
|
||||
case LexTokenKind::Int64Keyword: break;
|
||||
case LexTokenKind::IsKeyword: break;
|
||||
case LexTokenKind::MixinKeyword: break;
|
||||
case LexTokenKind::NamespaceKeyword: break;
|
||||
case LexTokenKind::NotKeyword: break;
|
||||
case LexTokenKind::NullKeyword: break;
|
||||
case LexTokenKind::OrKeyword: break;
|
||||
case LexTokenKind::OutKeyword: break;
|
||||
case LexTokenKind::OverrideKeyword: break;
|
||||
case LexTokenKind::PrivateKeyword: break;
|
||||
case LexTokenKind::PropertyKeyword: break;
|
||||
case LexTokenKind::ProtectedKeyword: break;
|
||||
case LexTokenKind::ReturnKeyword: break;
|
||||
case LexTokenKind::SetKeyword: break;
|
||||
case LexTokenKind::SharedKeyword: break;
|
||||
case LexTokenKind::SuperKeyword: break;
|
||||
case LexTokenKind::SwitchKeyword: break;
|
||||
case LexTokenKind::ThisKeyword: break;
|
||||
case LexTokenKind::TrueKeyword: break;
|
||||
case LexTokenKind::TryKeyword: break;
|
||||
case LexTokenKind::TypedefKeyword: break;
|
||||
case LexTokenKind::UintKeyword: break;
|
||||
case LexTokenKind::Uint8Keyword: break;
|
||||
case LexTokenKind::Uint16Keyword: break;
|
||||
case LexTokenKind::Uint32Keyword: break;
|
||||
case LexTokenKind::Uint64Keyword: break;
|
||||
case LexTokenKind::VoidKeyword: break;
|
||||
case LexTokenKind::WhileKeyword: break;
|
||||
case LexTokenKind::XorKeyword: break;
|
||||
case LexTokenKind::FloatLiteral: break;
|
||||
case LexTokenKind::IntegerLiteral: break;
|
||||
case LexTokenKind::StringLiteral: break;
|
||||
case LexTokenKind::Identifier: break;
|
||||
}
|
||||
return "FAIL";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MALACHSCRIPT_LEXTOKENKIND_HPP
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "Parser.hpp"
|
||||
#include <iostream>
|
||||
#include "../CoreData/PrimitiveTypes.hpp"
|
||||
#include "../Diagnostics/DiagnosticTypeEN_US.hpp"
|
||||
|
||||
#define PROGRESS_TOKEN(token) \
|
||||
token = (token)->GetNext().get(); \
|
||||
|
@ -10,7 +11,7 @@
|
|||
|
||||
#define EXPECT_TOKEN(token, kind) \
|
||||
if ((token)->GetKind() != LexTokenKind::kind) { \
|
||||
logError(DiagnosticType::UnexpectedToken, (token)->GetSpan()); \
|
||||
logError(DiagnosticType::UnexpectedToken, (token)->GetSpan(), {}); \
|
||||
if ((token)->GetNext() != nullptr && (token)->GetNext()->GetNext() != nullptr && \
|
||||
(token)->GetNext()->GetKind() == LexTokenKind::kind) { \
|
||||
(token) = (token)->GetNext()->GetNext().get(); \
|
||||
|
@ -19,7 +20,7 @@
|
|||
PROGRESS_TOKEN(token); \
|
||||
}
|
||||
|
||||
#define logError(type, span) log(DiagnosticLevel::Error, type, span)
|
||||
#define logError(type, span, formats) log(DiagnosticLevel::Error, type, span, formats)
|
||||
|
||||
namespace MalachScript::Parser {
|
||||
using namespace Diagnostics;
|
||||
|
@ -27,8 +28,8 @@ namespace MalachScript::Parser {
|
|||
const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, std::u8string_view scriptName,
|
||||
Logger* diagnostics) {
|
||||
const log_func& log = [diagnostics, scriptName](DiagnosticLevel level, DiagnosticType type,
|
||||
const TextSpan& span) {
|
||||
diagnostics->Log(level, type, scriptName, span);
|
||||
const TextSpan& span, const std::vector<std::string>& formats) {
|
||||
diagnostics->Log(level, type, scriptName, span, formats);
|
||||
};
|
||||
|
||||
ScopedPtr<const ParsedStatement> s = nullptr;
|
||||
|
@ -63,7 +64,8 @@ namespace MalachScript::Parser {
|
|||
auto result = ParseTypeDef(statement, current, log) || ParseClass(statement, current, log) ||
|
||||
ParseFunc(statement, current, log) || ParseNamespace(statement, current, log);
|
||||
if (!result) {
|
||||
logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
log(DiagnosticLevel::Error, DiagnosticType::UnexpectedToken, current->GetSpan(),
|
||||
{"", current->ToString()});
|
||||
PROGRESS_TOKEN(current);
|
||||
continue;
|
||||
}
|
||||
|
@ -98,7 +100,7 @@ namespace MalachScript::Parser {
|
|||
// After class keyword, an identifier should always follow, if it doesn't, log an error.
|
||||
Identifier identifier;
|
||||
if (!ParseIdentifier(identifier, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
PROGRESS_TOKEN(current);
|
||||
|
@ -114,21 +116,21 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current);
|
||||
Identifier id;
|
||||
if (!ParseIdentifier(id, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
inherits.push_back(id);
|
||||
while (current->GetKind() == LexTokenKind::CommaSymbol) {
|
||||
PROGRESS_TOKEN(current);
|
||||
if (!ParseIdentifier(id, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
inherits.push_back(id);
|
||||
PROGRESS_TOKEN(current);
|
||||
}
|
||||
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
@ -146,14 +148,14 @@ namespace MalachScript::Parser {
|
|||
// TODO: Sort by complexity
|
||||
if (!ParseVirtProp(statement, current, log) && !ParseFunc(statement, current, log) &&
|
||||
!ParseVar(statement, current, log) && !ParseFuncDef(statement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
break;
|
||||
}
|
||||
body.push_back(statement.TakeOwnership());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: logError(DiagnosticType::UnexpectedToken, current->GetSpan()); return false;
|
||||
default: logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {}); return false;
|
||||
}
|
||||
out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), classAttr, identifier, inherits,
|
||||
body);
|
||||
|
@ -170,13 +172,13 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current);
|
||||
Identifier defineFrom;
|
||||
if (!ParsePrimType(defineFrom, current, log) && !ParseIdentifier(defineFrom, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
|
||||
PROGRESS_TOKEN(current);
|
||||
Identifier defineTo;
|
||||
if (!ParseIdentifier(defineTo, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
PROGRESS_TOKEN(current);
|
||||
EXPECT_TOKEN(current, SemicolonSymbol);
|
||||
|
@ -193,14 +195,14 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current);
|
||||
Identifier identifier;
|
||||
if (!ParseIdentifier(identifier, current)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
} else {
|
||||
PROGRESS_TOKEN(current);
|
||||
}
|
||||
EXPECT_TOKEN(current, OpenCurlyParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> script = nullptr;
|
||||
if (!ParseScript(script, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
auto end = current->GetSpan().GetEnd();
|
||||
EXPECT_TOKEN(current, CloseCurlyParenthesisSymbol);
|
||||
|
@ -266,7 +268,7 @@ namespace MalachScript::Parser {
|
|||
ScopedPtr<const ParsedStatement> statblock = nullptr;
|
||||
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||
if (!ParseStatBlock(statblock, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -298,7 +300,7 @@ namespace MalachScript::Parser {
|
|||
if (token->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) {
|
||||
PROGRESS_TOKEN(token);
|
||||
if (token->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) {
|
||||
logError(DiagnosticType::UnexpectedToken, token->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, token->GetSpan(), {});
|
||||
} else {
|
||||
PROGRESS_TOKEN(token);
|
||||
isArray = true;
|
||||
|
@ -346,7 +348,7 @@ namespace MalachScript::Parser {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan(), {});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -410,11 +412,11 @@ namespace MalachScript::Parser {
|
|||
const ParsedStatement* defaultExpression = nullptr;
|
||||
|
||||
if (!ParseType(typeStatement, currentToken, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan(), {});
|
||||
}
|
||||
ParseTypeMod(typeMod, currentToken, log);
|
||||
if (!ParseIdentifier(identifier, currentToken)) {
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, currentToken->GetSpan(), {});
|
||||
} else {
|
||||
PROGRESS_TOKEN(currentToken);
|
||||
}
|
||||
|
@ -501,14 +503,14 @@ namespace MalachScript::Parser {
|
|||
ParseFuncAttr(getAttr, current, log);
|
||||
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||
if (!ParseStatBlock(getStatement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
} else {
|
||||
PROGRESS_TOKEN(current);
|
||||
}
|
||||
|
||||
if (hasGet) {
|
||||
logError(DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd()));
|
||||
logError(DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd()), {});
|
||||
}
|
||||
hasGet = true;
|
||||
} else if (current->GetKind() == LexTokenKind::SetKeyword) {
|
||||
|
@ -520,14 +522,14 @@ namespace MalachScript::Parser {
|
|||
ParseFuncAttr(setAttr, current, log);
|
||||
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
||||
if (!ParseStatBlock(setStatement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
} else {
|
||||
PROGRESS_TOKEN(current);
|
||||
}
|
||||
|
||||
if (hasSet) {
|
||||
logError(DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd()));
|
||||
logError(DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd()), {});
|
||||
}
|
||||
hasSet = true;
|
||||
} else {
|
||||
|
@ -535,7 +537,7 @@ namespace MalachScript::Parser {
|
|||
}
|
||||
}
|
||||
if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
} else {
|
||||
PROGRESS_TOKEN(current);
|
||||
}
|
||||
|
@ -558,18 +560,18 @@ namespace MalachScript::Parser {
|
|||
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> condition = nullptr;
|
||||
if (!ParseAssign(condition, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> body = nullptr;
|
||||
if (!ParseStatement(body, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
ScopedPtr<const ParsedStatement> elseStatement = nullptr;
|
||||
if (current->GetKind() == LexTokenKind::ElseKeyword) {
|
||||
PROGRESS_TOKEN(current);
|
||||
if (!ParseStatement(elseStatement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
}
|
||||
out = new ParsedIfStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
|
||||
|
@ -647,7 +649,7 @@ namespace MalachScript::Parser {
|
|||
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
||||
PROGRESS_TOKEN(current);
|
||||
} else {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
|
||||
out = new ParsedStatBlockStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
|
||||
|
@ -717,7 +719,7 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current);
|
||||
ScopedPtr<const ParsedStatement> rightHand = nullptr;
|
||||
if (!ParseAssign(rightHand, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
out = leftHand.TakeOwnership();
|
||||
currentToken = current;
|
||||
return true;
|
||||
|
@ -741,7 +743,7 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current); \
|
||||
ScopedPtr<const ParsedStatement> rightHand = nullptr; \
|
||||
if (!ParseExprTerm(rightHand, current, log)) { \
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan()); \
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {}); \
|
||||
out = leftHand.TakeOwnership(); \
|
||||
currentToken = current; \
|
||||
return true; \
|
||||
|
@ -826,7 +828,7 @@ namespace MalachScript::Parser {
|
|||
if (current->GetKind() == LexTokenKind::OpenParenthesisSymbol) {
|
||||
PROGRESS_TOKEN(current);
|
||||
if (!ParseAssign(out, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
}
|
||||
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
||||
currentToken = current;
|
||||
|
@ -940,12 +942,12 @@ namespace MalachScript::Parser {
|
|||
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> init;
|
||||
if (!ParseVar(init, current, log) && !ParseExprStat(init, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
ScopedPtr<const ParsedStatement> condition;
|
||||
if (!ParseExprStat(condition, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
std::vector<const ParsedStatement*> increment;
|
||||
|
@ -961,7 +963,7 @@ namespace MalachScript::Parser {
|
|||
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> statementBlock;
|
||||
if (!ParseStatement(statementBlock, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -982,13 +984,13 @@ namespace MalachScript::Parser {
|
|||
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> condition = nullptr;
|
||||
if (!ParseAssign(condition, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> body = nullptr;
|
||||
if (!ParseStatement(body, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
out = new ParsedWhileStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
|
||||
|
@ -1005,14 +1007,14 @@ namespace MalachScript::Parser {
|
|||
PROGRESS_TOKEN(current);
|
||||
ScopedPtr<const ParsedStatement> body = nullptr;
|
||||
if (!ParseStatement(body, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
EXPECT_TOKEN(current, WhileKeyword);
|
||||
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> condition = nullptr;
|
||||
if (!ParseAssign(condition, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
||||
|
@ -1032,13 +1034,13 @@ namespace MalachScript::Parser {
|
|||
|
||||
ScopedPtr<const ParsedStatement> tryStatement = nullptr;
|
||||
if (!ParseStatBlock(tryStatement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
EXPECT_TOKEN(current, CatchKeyword);
|
||||
ScopedPtr<const ParsedStatement> catchStatement = nullptr;
|
||||
if (!ParseStatBlock(catchStatement, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1057,7 +1059,7 @@ namespace MalachScript::Parser {
|
|||
EXPECT_TOKEN(currentToken, OpenParenthesisSymbol);
|
||||
ScopedPtr<const ParsedStatement> expression = nullptr;
|
||||
if (!ParseExpr(expression, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
EXPECT_TOKEN(currentToken, CloseParenthesisSymbol);
|
||||
|
@ -1078,7 +1080,7 @@ namespace MalachScript::Parser {
|
|||
}
|
||||
caseStatements.push_back(stat.TakeOwnership());
|
||||
} else {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1104,7 +1106,7 @@ namespace MalachScript::Parser {
|
|||
ScopedPtr<const ParsedStatement> expression = nullptr;
|
||||
if (!isDefault) {
|
||||
if (!ParseExpr(expression, current, log)) {
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan());
|
||||
logError(DiagnosticType::UnexpectedToken, current->GetSpan(), {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace MalachScript::Parser {
|
|||
Diagnostics::Logger* diagnostics);
|
||||
|
||||
private:
|
||||
using log_func =
|
||||
const std::function<void(Diagnostics::DiagnosticLevel level, Diagnostics::DiagnosticType, const TextSpan&)>;
|
||||
using log_func = const std::function<void(Diagnostics::DiagnosticLevel level, Diagnostics::DiagnosticType,
|
||||
const TextSpan&, const std::vector<std::string>&)>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Underlying functions are laid out in the order they are defined in the grammar.ebnf //
|
||||
|
|
Loading…
Reference in New Issue