- 增加了对 Lambda 表达式的初步解析支持,包括参数处理和返回类型。Lambda闭包尚未支持。 - 引入了用于对象初始化的新的表达式,支持可选的命名参数。 - 改进了表达式语法错误的错误报告。 - 更新了解析器和分析器以处理新的表达式类型并验证其语义。 - 修改了现有测试以涵盖新功能并确保其正确性。 - 改进了各种解析和语义错误的诊断。
201 lines
7.1 KiB
C++
201 lines
7.1 KiB
C++
/*!
|
|
@file src/Error/Error.cpp
|
|
@brief 错误报告实现
|
|
@author PuqiAR (im@puqiar.top)
|
|
@date 2026-02-14
|
|
*/
|
|
|
|
#include <Core/Core.hpp>
|
|
#include <Error/Error.hpp>
|
|
|
|
#include <sstream>
|
|
|
|
namespace Fig
|
|
{
|
|
void ColoredPrint(const char *color, const char *msg, std::ostream &ost = CoreIO::GetStdErr())
|
|
{
|
|
ost << color << msg << TerminalColors::Reset;
|
|
}
|
|
|
|
void
|
|
ColoredPrint(const char *color, const std::string &msg, std::ostream &ost = CoreIO::GetStdErr())
|
|
{
|
|
ost << color << msg << TerminalColors::Reset;
|
|
}
|
|
|
|
void ColoredPrint(const char *color, const String &msg, std::ostream &ost = CoreIO::GetStdErr())
|
|
{
|
|
ost << color << msg << TerminalColors::Reset;
|
|
}
|
|
|
|
std::string MultipleStr(const char *c, size_t n)
|
|
{
|
|
std::string buf;
|
|
for (size_t i = 0; i < n; ++i)
|
|
{
|
|
buf += c;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
const char *ErrorTypeToString(ErrorType type)
|
|
{
|
|
using enum ErrorType;
|
|
switch (type)
|
|
{
|
|
case UnusedSymbol: return "UnusedSymbol";
|
|
case UnnecessarySemicolon: return "UnnecessarySemicolon";
|
|
|
|
case MayBeNull: return "MaybeNull";
|
|
|
|
case UnterminatedString: return "UnterminatedString";
|
|
case UnterminatedComments: return "UnterminatedComments";
|
|
case InvalidNumberLiteral: return "InvalidNumberLiteral";
|
|
case InvalidCharacter: return "InvalidCharacter";
|
|
case InvalidSymbol: return "InvalidSymbol";
|
|
|
|
case ExpectedExpression: return "ExpectedExpression";
|
|
case SyntaxError: return "SyntaxError";
|
|
|
|
case RedeclarationError: return "RedeclarationError";
|
|
case UseUndeclaredIdentifier: return "UseUndeclaredIdentifier";
|
|
case NotAnLvalue: return "NotAnLvalue";
|
|
case TypeError: return "TypeError";
|
|
|
|
case TooManyLocals: return "TooManyLocals";
|
|
case TooManyConstants: return "TooManyConstants";
|
|
|
|
case RegisterOverflow: return "RegisterOverflow";
|
|
case InternalError:
|
|
return "InternalError";
|
|
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
|
}
|
|
return "UnknownError";
|
|
}
|
|
|
|
void PrintSystemInfos()
|
|
{
|
|
std::ostream &err = CoreIO::GetStdErr();
|
|
std::stringstream build_info;
|
|
build_info << "\r🌘 Fig v" << Core::VERSION << " on " << Core::PLATFORM << ' ' << Core::ARCH
|
|
<< '[' << Core::COMPILER << ']' << '\n'
|
|
<< " Build Time: " << Core::COMPILE_TIME;
|
|
|
|
const std::string &build_info_str = build_info.str();
|
|
err << MultipleStr("─", build_info_str.size()) << '\n';
|
|
err << build_info_str << '\n';
|
|
err << MultipleStr("─", build_info_str.size()) << '\n';
|
|
}
|
|
|
|
void PrintErrorInfo(const Error &error, const SourceManager &srcManager)
|
|
{
|
|
static constexpr const char *MinorColor = "\033[38;2;138;227;198m";
|
|
static constexpr const char *MediumColor = "\033[38;2;255;199;95m";
|
|
static constexpr const char *CriticalColor = "\033[38;2;255;107;107m";
|
|
|
|
namespace TC = TerminalColors;
|
|
std::ostream &err = CoreIO::GetStdErr();
|
|
|
|
uint8_t level = ErrorLevel(error.type);
|
|
// const char *level_name = (level == 1 ? "Minor" : (level == 2 ? "Medium" : "Critical"));
|
|
const char *level_color =
|
|
(level == 1 ? MinorColor : (level == 2 ? MediumColor : CriticalColor));
|
|
|
|
err << "🔥 "
|
|
<< level_color
|
|
//<< '(' << level_name << ')'
|
|
<< 'E' << static_cast<int>(error.type) << TC::Reset << ": " << level_color
|
|
<< ErrorTypeToString(error.type) << TC::Reset << '\n';
|
|
|
|
const SourceLocation &location = error.location;
|
|
|
|
err << TC::DarkGray << " ┌─> Fn " << TC::Cyan << '\'' << location.packageName << '.'
|
|
<< location.functionName << '\'' << " " << location.fileName << " (" << TC::DarkGray
|
|
<< location.sp.line << ":" << location.sp.column << TC::Cyan << ')' << TC::Reset
|
|
<< '\n';
|
|
err << TC::DarkGray << " │" << '\n' << " │" << TC::Reset << '\n';
|
|
|
|
// 尝试打印上3行 下2行
|
|
|
|
int64_t line_start = location.sp.line - 3, line_end = location.sp.line + 2;
|
|
while (!srcManager.HasLine(line_end))
|
|
{
|
|
--line_end;
|
|
}
|
|
while (!srcManager.HasLine(line_start))
|
|
{
|
|
++line_start;
|
|
}
|
|
|
|
const auto &getLineNumWidth = [](size_t l) {
|
|
unsigned int cnt = 0;
|
|
while (l != 0)
|
|
{
|
|
l = l / 10;
|
|
cnt++;
|
|
}
|
|
return cnt;
|
|
};
|
|
unsigned int max_line_number_width = getLineNumWidth(line_end);
|
|
for (size_t i = line_start; i <= line_end; ++i)
|
|
{
|
|
unsigned int offset = 2 + 2 + 1;
|
|
// ' └─ '
|
|
if (i == location.sp.line)
|
|
{
|
|
err << TC::DarkGray << " └─ " << TC::Reset;
|
|
}
|
|
else if (i < location.sp.line)
|
|
{
|
|
err << TC::DarkGray << " │ " << TC::Reset;
|
|
}
|
|
else
|
|
{
|
|
err << MultipleStr(" ", offset);
|
|
}
|
|
unsigned int cur_line_number_width = getLineNumWidth(i);
|
|
|
|
err << MultipleStr(" ", max_line_number_width - cur_line_number_width) << TC::Yellow
|
|
<< i << TC::Reset;
|
|
err << " │ " << srcManager.GetLine(i) << '\n';
|
|
if (i == location.sp.line)
|
|
{
|
|
unsigned int error_col_offset = offset + 1 + max_line_number_width + 2;
|
|
err << MultipleStr(" ", error_col_offset)
|
|
<< MultipleStr(" ", location.sp.column - 1) << TC::LightGreen
|
|
<< MultipleStr("^", location.sp.tok_length) << TC::Reset << '\n';
|
|
|
|
err << MultipleStr(" ", error_col_offset)
|
|
<< MultipleStr(" ", location.sp.column - 1 + location.sp.tok_length / 2)
|
|
<< "╰─ " << level_color << error.message << TC::Reset << "\n\n";
|
|
}
|
|
}
|
|
err << "\n";
|
|
err << "❓ " << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " ("
|
|
<< error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset
|
|
<< "\n";
|
|
err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset;
|
|
err << '\n';
|
|
}
|
|
|
|
void ReportError(const Error &error, const SourceManager &srcManager)
|
|
{
|
|
assert(srcManager.read && "ReportError: srcManager doesn't read source");
|
|
// assert(srcManager.HasLine(error.location.sp.line));
|
|
|
|
PrintSystemInfos();
|
|
PrintErrorInfo(error, srcManager);
|
|
}
|
|
|
|
void ReportErrors(const std::vector<Error> &errors, const SourceManager &srcManager)
|
|
{
|
|
std::ostream &ost = CoreIO::GetStdErr();
|
|
PrintSystemInfos();
|
|
for (const auto &err : errors)
|
|
{
|
|
PrintErrorInfo(err, srcManager);
|
|
ost << '\n';
|
|
}
|
|
}
|
|
}; // namespace Fig
|