2750 lines
81 KiB
C++
2750 lines
81 KiB
C++
#include "debug_printer.hpp"
|
|
#include <sstream>
|
|
|
|
namespace lsp::language::ast::debug
|
|
{
|
|
// ===== 辅助函数实现 =====
|
|
|
|
void DebugPrinter::Print(const ASTNode* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
os_ << GetColor(Color::Gray) << "<null>" << GetColor(Color::Reset) << "\n";
|
|
return;
|
|
}
|
|
const_cast<ASTNode*>(node)->Accept(*this);
|
|
}
|
|
|
|
void DebugPrinter::PrintStatements(const std::vector<StatementPtr>& statements)
|
|
{
|
|
for (size_t i = 0; i < statements.size(); ++i)
|
|
{
|
|
bool is_last = (i == statements.size() - 1);
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatement(statements[i].get(), "", is_last);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintParseResult(const ParseResult& result)
|
|
{
|
|
if (result.HasErrors())
|
|
{
|
|
os_ << GetColor(Color::BrightRed) << "Parse Errors:\n"
|
|
<< GetColor(Color::Reset);
|
|
for (const auto& error : result.errors)
|
|
{
|
|
PrintError(error);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
if (result.root)
|
|
{
|
|
Print(result.root.get());
|
|
}
|
|
}
|
|
|
|
// ===== 缩进和树形结构 =====
|
|
|
|
void DebugPrinter::PrintIndent(std::optional<bool> is_last)
|
|
{
|
|
if (!options_.use_tree_chars)
|
|
{
|
|
os_ << std::string(current_indent_, ' ');
|
|
return;
|
|
}
|
|
|
|
if (is_last.has_value())
|
|
{
|
|
// When the caller provides is_last, we treat current stack entries as ancestors.
|
|
for (size_t i = 0; i < is_last_child_stack_.size(); ++i)
|
|
{
|
|
os_ << (is_last_child_stack_[i] ? " " : "│ ");
|
|
}
|
|
os_ << (is_last.value() ? "└─ " : "├─ ");
|
|
return;
|
|
}
|
|
|
|
// Default behavior: draw the branch for the current node itself.
|
|
if (is_last_child_stack_.empty())
|
|
return;
|
|
|
|
bool is_last_val = is_last_child_stack_.back();
|
|
for (size_t i = 0; i < is_last_child_stack_.size(); ++i)
|
|
{
|
|
if (i == is_last_child_stack_.size() - 1)
|
|
{
|
|
os_ << (is_last_val ? "└─ " : "├─ ");
|
|
}
|
|
else
|
|
{
|
|
os_ << (is_last_child_stack_[i] ? " " : "│ ");
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintTreePrefix(bool is_last)
|
|
{
|
|
if (!options_.use_tree_chars)
|
|
{
|
|
os_ << std::string(current_indent_, ' ');
|
|
return;
|
|
}
|
|
|
|
for (size_t i = 0; i < is_last_child_stack_.size(); ++i)
|
|
{
|
|
os_ << (is_last_child_stack_[i] ? " " : "│ ");
|
|
}
|
|
os_ << (is_last ? "└─ " : "├─ ");
|
|
}
|
|
|
|
std::string DebugPrinter::GetIndent() const
|
|
{
|
|
return std::string(current_indent_, ' ');
|
|
}
|
|
|
|
void DebugPrinter::EmitChildren(std::vector<std::function<void(bool)>>&& children)
|
|
{
|
|
size_t count = children.size();
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
children[i](i == count - 1);
|
|
}
|
|
}
|
|
|
|
// ===== 颜色辅助 =====
|
|
|
|
const char* DebugPrinter::GetColor(const char* color) const
|
|
{
|
|
return options_.use_colors ? color : "";
|
|
}
|
|
|
|
void DebugPrinter::PrintColored(const std::string& text, const char* color)
|
|
{
|
|
os_ << GetColor(color) << text << GetColor(Color::Reset);
|
|
}
|
|
|
|
// ===== 节点信息输出 =====
|
|
|
|
void DebugPrinter::PrintNodeHeader(const std::string& type_name, const Location& loc)
|
|
{
|
|
PrintIndent();
|
|
PrintColored(type_name, Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(loc);
|
|
}
|
|
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintLocation(const Location& loc)
|
|
{
|
|
os_ << GetColor(Color::Gray) << "["
|
|
<< loc.start_line << ":" << loc.start_column << " - "
|
|
<< loc.end_line << ":" << loc.end_column << "]"
|
|
<< GetColor(Color::Reset);
|
|
}
|
|
|
|
void DebugPrinter::PrintSourceSnippet(const Location& loc, bool is_last_child)
|
|
{
|
|
if (!source_code_)
|
|
return;
|
|
|
|
std::string snippet = GetSourceText(loc);
|
|
if (snippet.empty())
|
|
return;
|
|
|
|
snippet = TruncateString(snippet, options_.max_source_length);
|
|
snippet = EscapeString(snippet);
|
|
|
|
os_ << "\n";
|
|
PrintIndent(is_last_child);
|
|
os_ << GetColor(Color::Dim) << "Source: \"" << snippet << "\""
|
|
<< GetColor(Color::Reset) << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const Location& location, const char* value_color, std::optional<bool> is_last)
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(key + ": ", Color::Yellow);
|
|
PrintColored(value, value_color ? value_color : Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(location);
|
|
}
|
|
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const char* value_color, std::optional<bool> is_last)
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(key + ": ", Color::Yellow);
|
|
PrintColored(value, value_color ? value_color : Color::Green);
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintKeyValue(const std::string& key, int value, std::optional<bool> is_last)
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(key + ": ", Color::Yellow);
|
|
os_ << value << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintKeyValue(const std::string& key, bool value, std::optional<bool> is_last)
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(key + ": ", Color::Yellow);
|
|
PrintColored(value ? "true" : "false", value ? Color::BrightGreen : Color::BrightRed);
|
|
os_ << "\n";
|
|
}
|
|
|
|
// ===== 表达式和语句打印 =====
|
|
|
|
void DebugPrinter::PrintExpression(const Expression* expr, const std::string& label, bool is_last)
|
|
{
|
|
if (!expr)
|
|
{
|
|
PrintIndent(is_last);
|
|
if (!label.empty())
|
|
{
|
|
PrintColored(label + ": ", Color::Yellow);
|
|
}
|
|
PrintColored("<null>", Color::Gray);
|
|
os_ << "\n";
|
|
return;
|
|
}
|
|
|
|
if (!label.empty())
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(label + ":", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
// Treat label as a tree node with a single child.
|
|
is_last_child_stack_.push_back(is_last);
|
|
is_last_child_stack_.push_back(true);
|
|
const_cast<Expression*>(expr)->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
return;
|
|
}
|
|
|
|
is_last_child_stack_.push_back(is_last);
|
|
const_cast<Expression*>(expr)->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
|
|
void DebugPrinter::PrintStatement(const Statement* stmt, const std::string& label, bool is_last)
|
|
{
|
|
if (!stmt)
|
|
{
|
|
PrintIndent(is_last);
|
|
if (!label.empty())
|
|
{
|
|
PrintColored(label + ": ", Color::Yellow);
|
|
}
|
|
PrintColored("<null>", Color::Gray);
|
|
os_ << "\n";
|
|
return;
|
|
}
|
|
|
|
if (!label.empty())
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(label + ":", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
// Treat label as a tree node with a single child.
|
|
is_last_child_stack_.push_back(is_last);
|
|
is_last_child_stack_.push_back(true);
|
|
const_cast<Statement*>(stmt)->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
return;
|
|
}
|
|
|
|
is_last_child_stack_.push_back(is_last);
|
|
const_cast<Statement*>(stmt)->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
|
|
void DebugPrinter::PrintParameter(const Parameter& param, bool is_last)
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored("Parameter: ", Color::Cyan);
|
|
PrintColored("\"" + param.name + "\"", Color::Green);
|
|
|
|
if (param.type)
|
|
{
|
|
os_ << " : ";
|
|
PrintColored(param.type->name, Color::BrightYellow);
|
|
}
|
|
|
|
switch (param.mode)
|
|
{
|
|
case ast::ParameterMode::kNone:
|
|
break;
|
|
case ast::ParameterMode::kConst:
|
|
os_ << " " << GetColor(Color::Magenta) << "(const)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kIn:
|
|
os_ << " " << GetColor(Color::Magenta) << "(in)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kOut:
|
|
os_ << " " << GetColor(Color::Magenta) << "(out)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kVar:
|
|
os_ << " " << GetColor(Color::Magenta) << "(var)" << GetColor(Color::Reset);
|
|
break;
|
|
}
|
|
|
|
if (param.default_value)
|
|
{
|
|
os_ << " = <expr>";
|
|
}
|
|
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintLeftHandSide(const LValue& lhs, const std::string& label, bool is_last)
|
|
{
|
|
std::visit([&](auto&& value) {
|
|
using T = std::decay_t<decltype(value)>;
|
|
|
|
if constexpr (std::is_same_v<T, std::monostate>)
|
|
{
|
|
PrintIndent(is_last);
|
|
if (!label.empty())
|
|
{
|
|
PrintColored(label + ": ", Color::Yellow);
|
|
}
|
|
PrintColored("<empty>", Color::Gray);
|
|
os_ << "\n";
|
|
}
|
|
else if constexpr (std::is_same_v<T, ExpressionPtr>)
|
|
{
|
|
PrintExpression(value.get(), label, is_last);
|
|
}
|
|
else if constexpr (std::is_same_v<T, std::unique_ptr<Identifier>> ||
|
|
std::is_same_v<T, std::unique_ptr<AttributeExpression>> ||
|
|
std::is_same_v<T, std::unique_ptr<SubscriptExpression>> ||
|
|
std::is_same_v<T, std::unique_ptr<ColumnReference>>)
|
|
{
|
|
if (!label.empty())
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(label + ":", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
// Label node wraps a single child.
|
|
is_last_child_stack_.push_back(is_last);
|
|
is_last_child_stack_.push_back(true);
|
|
if (value)
|
|
value->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
}
|
|
else
|
|
{
|
|
is_last_child_stack_.push_back(is_last);
|
|
if (value)
|
|
value->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
}
|
|
else if constexpr (std::is_same_v<T, std::unique_ptr<UnpackPattern>>)
|
|
{
|
|
if (!label.empty())
|
|
{
|
|
PrintIndent(is_last);
|
|
PrintColored(label + ":", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
// Label node wraps a single child.
|
|
is_last_child_stack_.push_back(is_last);
|
|
is_last_child_stack_.push_back(true);
|
|
if (value)
|
|
value->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
}
|
|
else
|
|
{
|
|
is_last_child_stack_.push_back(is_last);
|
|
if (value)
|
|
value->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
}
|
|
},
|
|
lhs);
|
|
}
|
|
|
|
// ===== 枚举值打印 =====
|
|
|
|
void DebugPrinter::PrintOperator(BinaryOperator op)
|
|
{
|
|
PrintColored(GetBinaryOperatorSymbol(op), Color::BrightMagenta);
|
|
}
|
|
|
|
void DebugPrinter::PrintOperator(AssignmentOperator op)
|
|
{
|
|
PrintColored(GetAssignmentOperatorSymbol(op), Color::BrightMagenta);
|
|
}
|
|
|
|
void DebugPrinter::PrintLiteralKind(LiteralKind kind)
|
|
{
|
|
const char* kind_str = "";
|
|
switch (kind)
|
|
{
|
|
case LiteralKind::kNumber:
|
|
kind_str = "Number";
|
|
break;
|
|
case LiteralKind::kString:
|
|
kind_str = "String";
|
|
break;
|
|
case LiteralKind::kChar:
|
|
kind_str = "Char";
|
|
break;
|
|
case LiteralKind::kBoolean:
|
|
kind_str = "Boolean";
|
|
break;
|
|
case LiteralKind::kNil:
|
|
kind_str = "Nil";
|
|
break;
|
|
case LiteralKind::kNan:
|
|
kind_str = "NaN";
|
|
break;
|
|
case LiteralKind::kInfinity:
|
|
kind_str = "Infinity";
|
|
break;
|
|
}
|
|
PrintColored(kind_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintAccessModifier(AccessModifier modifier)
|
|
{
|
|
const char* mod_str = "";
|
|
switch (modifier)
|
|
{
|
|
case AccessModifier::kPublic:
|
|
mod_str = "public";
|
|
break;
|
|
case AccessModifier::kProtected:
|
|
mod_str = "protected";
|
|
break;
|
|
case AccessModifier::kPrivate:
|
|
mod_str = "private";
|
|
break;
|
|
}
|
|
PrintColored(mod_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintMethodModifier(MethodModifier modifier)
|
|
{
|
|
const char* mod_str = "";
|
|
switch (modifier)
|
|
{
|
|
case MethodModifier::kNone:
|
|
mod_str = "none";
|
|
break;
|
|
case MethodModifier::kVirtual:
|
|
mod_str = "virtual";
|
|
break;
|
|
case MethodModifier::kOverride:
|
|
mod_str = "override";
|
|
break;
|
|
case MethodModifier::kOverload:
|
|
mod_str = "overload";
|
|
break;
|
|
}
|
|
PrintColored(mod_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintMethodType(MethodKind kind)
|
|
{
|
|
const char* type_str = "";
|
|
switch (kind)
|
|
{
|
|
case MethodKind::kOrdinary:
|
|
type_str = "ordinary";
|
|
break;
|
|
case MethodKind::kConstructor:
|
|
type_str = "constructor";
|
|
break;
|
|
case MethodKind::kDestructor:
|
|
type_str = "destructor";
|
|
break;
|
|
case MethodKind::kOperator:
|
|
type_str = "operator";
|
|
break;
|
|
}
|
|
PrintColored(type_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintReferenceModifier(ReferenceModifier modifier)
|
|
{
|
|
const char* mod_str = "";
|
|
switch (modifier)
|
|
{
|
|
case ReferenceModifier::kNone:
|
|
return;
|
|
case ReferenceModifier::kWeakRef:
|
|
mod_str = "weakref";
|
|
break;
|
|
case ReferenceModifier::kAutoRef:
|
|
mod_str = "autoref";
|
|
break;
|
|
}
|
|
PrintColored(mod_str, Color::Magenta);
|
|
}
|
|
|
|
void DebugPrinter::PrintConditionalCompilationType(ConditionalCompilationType type)
|
|
{
|
|
const char* type_str = "";
|
|
switch (type)
|
|
{
|
|
case ConditionalCompilationType::kIfDef:
|
|
type_str = "ifdef";
|
|
break;
|
|
case ConditionalCompilationType::kIfNDef:
|
|
type_str = "ifndef";
|
|
break;
|
|
case ConditionalCompilationType::kDefine:
|
|
type_str = "define";
|
|
break;
|
|
case ConditionalCompilationType::kUndef:
|
|
type_str = "undef";
|
|
break;
|
|
}
|
|
PrintColored(type_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintTSSQLExpressionType(TSSQLExpressionType type)
|
|
{
|
|
const char* type_str = "";
|
|
switch (type)
|
|
{
|
|
case TSSQLExpressionType::kSelect:
|
|
type_str = "select";
|
|
break;
|
|
case TSSQLExpressionType::kSSelect:
|
|
type_str = "sselect";
|
|
break;
|
|
case TSSQLExpressionType::kVSelect:
|
|
type_str = "vselect";
|
|
break;
|
|
case TSSQLExpressionType::kMSelect:
|
|
type_str = "mselect";
|
|
break;
|
|
case TSSQLExpressionType::kUpdate:
|
|
type_str = "update";
|
|
break;
|
|
case TSSQLExpressionType::kDelete:
|
|
type_str = "delete";
|
|
break;
|
|
case TSSQLExpressionType::kInsert:
|
|
type_str = "insert";
|
|
break;
|
|
}
|
|
PrintColored(type_str, Color::BrightYellow);
|
|
}
|
|
|
|
void DebugPrinter::PrintError(const ParseError& error)
|
|
{
|
|
os_ << GetColor(Color::BrightRed) << " Error: " << GetColor(Color::Reset)
|
|
<< error.message << "\n";
|
|
os_ << GetColor(Color::Gray) << " Location: ["
|
|
<< error.location.start_line << ":" << error.location.start_column << " - "
|
|
<< error.location.end_line << ":" << error.location.end_column << "]"
|
|
<< GetColor(Color::Reset) << "\n";
|
|
}
|
|
|
|
// ===== 工具函数 =====
|
|
|
|
std::string DebugPrinter::EscapeString(const std::string& str) const
|
|
{
|
|
std::string result;
|
|
for (char c : str)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\n':
|
|
result += "\\n";
|
|
break;
|
|
case '\r':
|
|
result += "\\r";
|
|
break;
|
|
case '\t':
|
|
result += "\\t";
|
|
break;
|
|
case '"':
|
|
result += "\\\"";
|
|
break;
|
|
case '\\':
|
|
result += "\\\\";
|
|
break;
|
|
default:
|
|
result += c;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string DebugPrinter::TruncateString(const std::string& str, size_t max_len) const
|
|
{
|
|
if (str.length() <= max_len)
|
|
return str;
|
|
return str.substr(0, max_len - 3) + "...";
|
|
}
|
|
|
|
std::string DebugPrinter::GetSourceText(const Location& loc) const
|
|
{
|
|
if (!source_code_)
|
|
return "";
|
|
if (loc.start_offset >= source_code_->length())
|
|
return "";
|
|
|
|
size_t length = loc.end_offset - loc.start_offset;
|
|
if (loc.start_offset + length > source_code_->length())
|
|
length = source_code_->length() - loc.start_offset;
|
|
|
|
return source_code_->substr(loc.start_offset, length);
|
|
}
|
|
|
|
std::string DebugPrinter::GetNodeKindName(NodeKind kind) const
|
|
{
|
|
switch (kind)
|
|
{
|
|
case NodeKind::kIdentifier:
|
|
return "kIdentifier";
|
|
case NodeKind::kLiteral:
|
|
return "kLiteral";
|
|
case NodeKind::kArrayExpression:
|
|
return "kArrayExpression";
|
|
case NodeKind::kParenthesizedExpression:
|
|
return "kParenthesizedExpression";
|
|
case NodeKind::kAttributeExpression:
|
|
return "kAttributeExpression";
|
|
case NodeKind::kSubscriptExpression:
|
|
return "kSubscriptExpression";
|
|
case NodeKind::kCallExpression:
|
|
return "kCallExpression";
|
|
case NodeKind::kUnaryPlusExpression:
|
|
return "kUnaryPlusExpression";
|
|
case NodeKind::kUnaryMinusExpression:
|
|
return "kUnaryMinusExpression";
|
|
case NodeKind::kPrefixIncrementExpression:
|
|
return "kPrefixIncrementExpression";
|
|
case NodeKind::kPrefixDecrementExpression:
|
|
return "kPrefixDecrementExpression";
|
|
case NodeKind::kPostfixIncrementExpression:
|
|
return "kPostfixIncrementExpression";
|
|
case NodeKind::kPostfixDecrementExpression:
|
|
return "kPostfixDecrementExpression";
|
|
case NodeKind::kLogicalNotExpression:
|
|
return "kLogicalNotExpression";
|
|
case NodeKind::kBitwiseNotExpression:
|
|
return "kBitwiseNotExpression";
|
|
case NodeKind::kDerivativeExpression:
|
|
return "kDerivativeExpression";
|
|
case NodeKind::kFunctionPointerExpression:
|
|
return "kFunctionPointerExpression";
|
|
case NodeKind::kMatrixTransposeExpression:
|
|
return "kMatrixTransposeExpression";
|
|
case NodeKind::kExprOperatorExpression:
|
|
return "kExprOperatorExpression";
|
|
case NodeKind::kBinaryExpression:
|
|
return "kBinaryExpression";
|
|
case NodeKind::kTernaryExpression:
|
|
return "kTernaryExpression";
|
|
case NodeKind::kAssignmentExpression:
|
|
return "kAssignmentExpression";
|
|
case NodeKind::kAnonymousFunctionExpression:
|
|
return "kAnonymousFunctionExpression";
|
|
case NodeKind::kNewExpression:
|
|
return "kNewExpression";
|
|
case NodeKind::kEchoExpression:
|
|
return "kEchoExpression";
|
|
case NodeKind::kRaiseExpression:
|
|
return "kRaiseExpression";
|
|
case NodeKind::kInheritedExpression:
|
|
return "kInheritedExpression";
|
|
case NodeKind::kTSSQLExpression:
|
|
return "kTSSQLExpression";
|
|
case NodeKind::kColumnReference:
|
|
return "kColumnReference";
|
|
case NodeKind::kUnpackPattern:
|
|
return "kUnpackPattern";
|
|
case NodeKind::kParameter:
|
|
return "kParameter";
|
|
case NodeKind::kVarDeclaration:
|
|
return "kVarDeclaration";
|
|
case NodeKind::kStaticDeclaration:
|
|
return "kStaticDeclaration";
|
|
case NodeKind::kGlobalDeclaration:
|
|
return "kGlobalDeclaration";
|
|
case NodeKind::kConstDeclaration:
|
|
return "kConstDeclaration";
|
|
case NodeKind::kFieldDeclaration:
|
|
return "kFieldDeclaration";
|
|
case NodeKind::kExpressionStatement:
|
|
return "kExpressionStatement";
|
|
case NodeKind::kBlockStatement:
|
|
return "kBlockStatement";
|
|
case NodeKind::kIfStatement:
|
|
return "kIfStatement";
|
|
case NodeKind::kForInStatement:
|
|
return "kForInStatement";
|
|
case NodeKind::kForToStatement:
|
|
return "kForToStatement";
|
|
case NodeKind::kWhileStatement:
|
|
return "kWhileStatement";
|
|
case NodeKind::kRepeatStatement:
|
|
return "kRepeatStatement";
|
|
case NodeKind::kCaseStatement:
|
|
return "kCaseStatement";
|
|
case NodeKind::kTryStatement:
|
|
return "kTryStatement";
|
|
case NodeKind::kBreakStatement:
|
|
return "kBreakStatement";
|
|
case NodeKind::kContinueStatement:
|
|
return "kContinueStatement";
|
|
case NodeKind::kReturnStatement:
|
|
return "kReturnStatement";
|
|
case NodeKind::kUsesStatement:
|
|
return "kUsesStatement";
|
|
case NodeKind::kFunctionDeclaration:
|
|
return "kFunctionDeclaration";
|
|
case NodeKind::kFunctionDefinition:
|
|
return "kFunctionDefinition";
|
|
case NodeKind::kMethodDeclaration:
|
|
return "kMethodDeclaration";
|
|
case NodeKind::kPropertyDeclaration:
|
|
return "kPropertyDeclaration";
|
|
case NodeKind::kClassMember:
|
|
return "kClassMember";
|
|
case NodeKind::kClassDefinition:
|
|
return "kClassDefinition";
|
|
case NodeKind::kExternalMethodDefinition:
|
|
return "kExternalMethodDefinition";
|
|
case NodeKind::kUnitDefinition:
|
|
return "kUnitDefinition";
|
|
case NodeKind::kMatrixIterationStatement:
|
|
return "kMatrixIterationStatement";
|
|
case NodeKind::kCompilerDirective:
|
|
return "kCompilerDirective";
|
|
case NodeKind::kConditionalBlock:
|
|
return "kConditionalBlock";
|
|
case NodeKind::kConditionalDirective:
|
|
return "kConditionalDirective";
|
|
case NodeKind::kTSLXBlock:
|
|
return "kTSLXBlock";
|
|
case NodeKind::kProgram:
|
|
return "kProgram";
|
|
default:
|
|
return "kUnknown";
|
|
}
|
|
}
|
|
|
|
// ===== Visitor 实现 - 基础节点 =====
|
|
|
|
void DebugPrinter::VisitProgram(Program& node)
|
|
{
|
|
PrintNodeHeader("Program", node.span);
|
|
|
|
bool has_source = options_.show_source_code && source_code_ && !GetSourceText(node.span).empty();
|
|
|
|
size_t child_count = node.statements.size();
|
|
if (has_source)
|
|
++child_count;
|
|
if (options_.show_node_kind)
|
|
++child_count;
|
|
|
|
size_t child_index = 0;
|
|
auto emit_child = [&](auto&& fn) {
|
|
bool is_last_child = ++child_index == child_count;
|
|
fn(is_last_child);
|
|
};
|
|
|
|
IncreaseIndent();
|
|
|
|
if (has_source)
|
|
{
|
|
emit_child([&](bool is_last) { PrintSourceSnippet(node.span, is_last); });
|
|
}
|
|
|
|
if (options_.show_node_kind)
|
|
{
|
|
emit_child([&](bool is_last) {
|
|
PrintKeyValue("Kind", GetNodeKindName(node.kind), node.span, nullptr, is_last);
|
|
});
|
|
}
|
|
|
|
for (const auto& stmt : node.statements)
|
|
{
|
|
emit_child([&](bool is_last) { PrintStatement(stmt.get(), "", is_last); });
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitUnitDefinition(UnitDefinition& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("UnitDefinition: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (!node.interface_statements.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Interface:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatements(node.interface_statements);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (!node.implementation_statements.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Implementation:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatements(node.implementation_statements);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (!node.initialization_statements.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Initialization:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatements(node.initialization_statements);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (!node.finalization_statements.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Finalization:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatements(node.finalization_statements);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitClassDefinition(ClassDefinition& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ClassDefinition: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (!node.parent_classes.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Parents:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
for (size_t i = 0; i < node.parent_classes.size(); ++i)
|
|
{
|
|
const auto& parent = node.parent_classes[i];
|
|
PrintIndent(i == node.parent_classes.size() - 1);
|
|
|
|
if (parent.qualifier)
|
|
{
|
|
PrintColored(*parent.qualifier + ".", Color::Magenta);
|
|
}
|
|
|
|
PrintColored(parent.name, Color::Green);
|
|
os_ << "\n";
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (node.uses)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
is_last_child_stack_.push_back(is_last);
|
|
node.uses->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
});
|
|
}
|
|
|
|
if (!node.members.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Members:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
for (size_t i = 0; i < node.members.size(); ++i)
|
|
{
|
|
is_last_child_stack_.push_back(i == node.members.size() - 1);
|
|
if (node.members[i])
|
|
node.members[i]->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitClassMember(ClassMember& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ClassMember", Color::BrightCyan);
|
|
|
|
if (node.access_modifier != AccessModifier::kPublic)
|
|
{
|
|
os_ << " (";
|
|
PrintAccessModifier(node.access_modifier);
|
|
os_ << ")";
|
|
}
|
|
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
// 处理 member variant
|
|
std::visit([this](auto&& member_ptr) {
|
|
if (member_ptr)
|
|
{
|
|
is_last_child_stack_.push_back(true);
|
|
member_ptr->Accept(*this);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
},
|
|
node.member);
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitMethodDeclaration(MethodDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("MethodDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.modifier != MethodModifier::kNone)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Modifier: ", Color::Yellow);
|
|
PrintMethodModifier(node.modifier);
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
if (node.method_kind != MethodKind::kOrdinary)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("MethodKind: ", Color::Yellow);
|
|
PrintMethodType(node.method_kind);
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
if (node.is_static)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("ClassMethod", true, is_last); });
|
|
}
|
|
|
|
if (!node.parameters.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Parameters:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
for (size_t i = 0; i < node.parameters.size(); ++i)
|
|
{
|
|
if (node.parameters[i])
|
|
{
|
|
PrintParameter(*node.parameters[i], i == node.parameters.size() - 1);
|
|
}
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (node.return_type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitPropertyDeclaration(PropertyDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("PropertyDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.index)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintExpression(node.index.value().get(), "Index", is_last); });
|
|
}
|
|
|
|
if (node.read_accessor)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Read: ", Color::Yellow);
|
|
PrintColored("\"" + node.read_accessor.value() + "\"", Color::Green);
|
|
if (options_.show_location && node.read_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.read_location.value());
|
|
}
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
if (node.write_accessor)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Write: ", Color::Yellow);
|
|
PrintColored("\"" + node.write_accessor.value() + "\"", Color::Green);
|
|
if (options_.show_location && node.write_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.write_location.value());
|
|
}
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitExternalMethodDefinition(ExternalMethodDefinition& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ExternalMethodDefinition: ", Color::BrightCyan);
|
|
PrintColored(node.owner_class.name + "::" + node.name, Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
size_t child_count = 0;
|
|
if (node.modifier != MethodModifier::kNone)
|
|
++child_count;
|
|
if (node.method_kind != MethodKind::kOrdinary)
|
|
++child_count;
|
|
if (!node.parameters.empty())
|
|
++child_count;
|
|
if (node.return_type)
|
|
++child_count;
|
|
if (node.body)
|
|
++child_count;
|
|
|
|
size_t child_index = 0;
|
|
auto emit_child = [&](auto&& fn) {
|
|
bool is_last_child = ++child_index == child_count;
|
|
fn(is_last_child);
|
|
};
|
|
|
|
IncreaseIndent();
|
|
|
|
if (node.modifier != MethodModifier::kNone)
|
|
{
|
|
emit_child([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Modifier: ", Color::Yellow);
|
|
PrintMethodModifier(node.modifier);
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
if (node.method_kind != MethodKind::kOrdinary)
|
|
{
|
|
emit_child([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("MethodKind: ", Color::Yellow);
|
|
PrintMethodType(node.method_kind);
|
|
os_ << "\n";
|
|
});
|
|
}
|
|
|
|
if (!node.parameters.empty())
|
|
{
|
|
emit_child([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Parameters:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.parameters.size(); ++i)
|
|
{
|
|
if (node.parameters[i])
|
|
{
|
|
PrintParameter(*node.parameters[i], i == node.parameters.size() - 1);
|
|
}
|
|
}
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (node.return_type)
|
|
{
|
|
emit_child([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.body)
|
|
{
|
|
emit_child([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 基础表达式 =====
|
|
|
|
void DebugPrinter::VisitIdentifier(Identifier& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Identifier: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitLiteral(Literal& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Literal: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.value + "\"", Color::Green);
|
|
os_ << " (";
|
|
PrintLiteralKind(node.literal_kind);
|
|
os_ << ")";
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitArrayExpression(ArrayExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ArrayExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (!node.elements.empty())
|
|
{
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.elements.size(); ++i)
|
|
{
|
|
const auto& elem = node.elements[i];
|
|
bool is_last = (i == node.elements.size() - 1);
|
|
|
|
if (elem.key)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Element:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
PrintExpression(elem.key->get(), "Key", false);
|
|
PrintExpression(elem.value.get(), "Value", true);
|
|
DecreaseIndent();
|
|
}
|
|
else
|
|
{
|
|
PrintExpression(elem.value.get(), "", is_last);
|
|
}
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitParenthesizedExpression(ParenthesizedExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ParenthesizedExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.elements.size(); ++i)
|
|
{
|
|
const auto& elem = node.elements[i];
|
|
bool is_last = (i == node.elements.size() - 1);
|
|
|
|
if (elem.key)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Element (key-value):", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
PrintExpression(elem.key.value().get(), "Key", false);
|
|
PrintExpression(elem.value.get(), "Value", is_last);
|
|
DecreaseIndent();
|
|
}
|
|
else
|
|
{
|
|
PrintExpression(elem.value.get(), "", is_last);
|
|
}
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 访问表达式 =====
|
|
|
|
void DebugPrinter::VisitCallExpression(CallExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("CallExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
PrintExpression(node.callee.get(), "Callee", node.arguments.empty());
|
|
|
|
if (!node.arguments.empty())
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Arguments:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.arguments.size(); ++i)
|
|
{
|
|
bool is_last = (i == node.arguments.size() - 1);
|
|
const auto& arg = node.arguments[i];
|
|
|
|
std::string label = "Argument";
|
|
if (arg.name)
|
|
{
|
|
label += " (" + arg.name.value() + ")";
|
|
}
|
|
if (arg.mode == ast::ParameterMode::kConst)
|
|
{
|
|
label += " [const]";
|
|
}
|
|
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintExpression(arg.value.get(), label, is_last);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitAttributeExpression(AttributeExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("AttributeExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.object.get(), "Object", false);
|
|
PrintExpression(node.attribute.get(), "Attribute", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitSubscriptExpression(SubscriptExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("SubscriptExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
PrintExpression(node.base.get(), "Base", node.indices.empty());
|
|
|
|
if (!node.indices.empty())
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Indices:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.indices.size(); ++i)
|
|
{
|
|
bool is_last = (i == node.indices.size() - 1);
|
|
const auto& idx = node.indices[i];
|
|
|
|
PrintIndent();
|
|
PrintColored("Index " + std::to_string(i), Color::Yellow);
|
|
if (idx.is_slice)
|
|
{
|
|
PrintColored(" (slice)", Color::Gray);
|
|
}
|
|
if (idx.is_empty_slice)
|
|
{
|
|
PrintColored(" (empty)", Color::Gray);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
if (idx.start)
|
|
{
|
|
is_last_child_stack_.push_back(false);
|
|
PrintExpression(idx.start.get(), "Start", !idx.end && !idx.step);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
if (idx.end)
|
|
{
|
|
is_last_child_stack_.push_back(false);
|
|
PrintExpression(idx.end.get(), "End", !idx.step);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
if (idx.step)
|
|
{
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintExpression(idx.step.get(), "Step", true);
|
|
is_last_child_stack_.pop_back();
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 一元表达式 =====
|
|
|
|
void DebugPrinter::VisitUnaryPlusExpression(UnaryPlusExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("UnaryPlusExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitUnaryMinusExpression(UnaryMinusExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("UnaryMinusExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitPrefixIncrementExpression(PrefixIncrementExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("PrefixIncrementExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitPrefixDecrementExpression(PrefixDecrementExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("PrefixDecrementExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitPostfixIncrementExpression(PostfixIncrementExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("PostfixIncrementExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitPostfixDecrementExpression(PostfixDecrementExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("PostfixDecrementExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitLogicalNotExpression(LogicalNotExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("LogicalNotExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitBitwiseNotExpression(BitwiseNotExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("BitwiseNotExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitDerivativeExpression(DerivativeExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("DerivativeExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitFunctionPointerExpression(FunctionPointerExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("FunctionPointerExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Argument", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitMatrixTransposeExpression(MatrixTransposeExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("MatrixTransposeExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitExprOperatorExpression(ExprOperatorExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ExprOperatorExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.argument.get(), "Operand", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 二元和三元表达式 =====
|
|
|
|
void DebugPrinter::VisitBinaryExpression(BinaryExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("BinaryExpression: ", Color::BrightCyan);
|
|
PrintOperator(node.op);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.left.get(), "Left", false);
|
|
PrintExpression(node.right.get(), "Right", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitTernaryExpression(TernaryExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("TernaryExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.condition.get(), "Condition", false);
|
|
PrintExpression(node.consequence.get(), "Consequence", false);
|
|
PrintExpression(node.alternative.get(), "Alternative", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitAssignmentExpression(AssignmentExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("AssignmentExpression: ", Color::BrightCyan);
|
|
PrintOperator(node.op);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintLeftHandSide(node.left, "Left", false);
|
|
PrintExpression(node.right.get(), "Right", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 特殊表达式 =====
|
|
|
|
void DebugPrinter::VisitAnonymousFunctionExpression(AnonymousFunctionExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("AnonymousFunctionExpression", Color::BrightCyan);
|
|
|
|
if (node.is_static)
|
|
{
|
|
os_ << " " << GetColor(Color::Magenta) << "(static)" << GetColor(Color::Reset);
|
|
}
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (!node.parameters.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Parameters:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
for (size_t i = 0; i < node.parameters.size(); ++i)
|
|
{
|
|
if (node.parameters[i])
|
|
{
|
|
PrintParameter(*node.parameters[i], i == node.parameters.size() - 1);
|
|
}
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (node.return_type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitNewExpression(NewExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("NewExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (node.target)
|
|
{
|
|
IncreaseIndent();
|
|
PrintExpression(node.target.get(), "Class", true);
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitEchoExpression(EchoExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("EchoExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (!node.expressions.empty())
|
|
{
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.expressions.size(); ++i)
|
|
{
|
|
PrintExpression(node.expressions[i].get(), "", i == node.expressions.size() - 1);
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitRaiseExpression(RaiseExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("RaiseExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.exception.get(), "Exception", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitInheritedExpression(InheritedExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("InheritedExpression", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (node.call)
|
|
{
|
|
IncreaseIndent();
|
|
PrintExpression(node.call.value().get(), "Call", true);
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitTSSQLExpression(TSSQLExpression& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("TSSQLExpression: ", Color::BrightCyan);
|
|
PrintTSSQLExpressionType(node.sql_type);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
PrintIndent();
|
|
PrintColored("SQL: ", Color::Yellow);
|
|
PrintColored("\"" + EscapeString(TruncateString(node.raw_sql, 100)) + "\"", Color::Green);
|
|
os_ << "\n";
|
|
|
|
if (options_.show_location)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("SQL Location: ", Color::Yellow);
|
|
PrintLocation(node.sql_location);
|
|
os_ << "\n";
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitColumnReference(ColumnReference& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ColumnReference", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (node.value)
|
|
{
|
|
IncreaseIndent();
|
|
PrintExpression(node.value.get(), "Value", true);
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
// ===== 模式 =====
|
|
|
|
void DebugPrinter::VisitParameter(Parameter& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Parameter: ", Color::Cyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (node.type)
|
|
{
|
|
os_ << " : ";
|
|
PrintColored(node.type->name, Color::BrightYellow);
|
|
}
|
|
|
|
switch (node.mode)
|
|
{
|
|
case ast::ParameterMode::kNone:
|
|
break;
|
|
case ast::ParameterMode::kConst:
|
|
os_ << " " << GetColor(Color::Magenta) << "(const)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kIn:
|
|
os_ << " " << GetColor(Color::Magenta) << "(in)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kOut:
|
|
os_ << " " << GetColor(Color::Magenta) << "(out)" << GetColor(Color::Reset);
|
|
break;
|
|
case ast::ParameterMode::kVar:
|
|
os_ << " " << GetColor(Color::Magenta) << "(var)" << GetColor(Color::Reset);
|
|
break;
|
|
}
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
|
|
os_ << "\n";
|
|
|
|
if (node.default_value)
|
|
{
|
|
IncreaseIndent();
|
|
PrintExpression(node.default_value->get(), "DefaultValue", true);
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitUnpackPattern(UnpackPattern& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("UnpackPattern", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (!node.elements.empty())
|
|
{
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.elements.size(); ++i)
|
|
{
|
|
bool is_last = (i == node.elements.size() - 1);
|
|
PrintLeftHandSide(node.elements[i], "Element", is_last);
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
// ===== 语句 =====
|
|
|
|
void DebugPrinter::VisitExpressionStatement(ExpressionStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ExpressionStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintExpression(node.expression.get(), "", true);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitBlockStatement(BlockStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("BlockStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
PrintStatements(node.statements);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitIfStatement(IfStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("IfStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
// If/ElseIf branches
|
|
for (size_t i = 0; i < node.branches.size(); ++i)
|
|
{
|
|
const auto& branch = node.branches[i];
|
|
children.push_back([&, i](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored(i == 0 ? "If Branch:" : "ElseIf Branch:", Color::Yellow);
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
|
|
std::vector<std::function<void(bool)>> branch_children;
|
|
branch_children.push_back([&](bool inner_last) { PrintExpression(branch.condition.get(), "Condition", inner_last); });
|
|
if (branch.body)
|
|
{
|
|
branch_children.push_back([&](bool inner_last) { PrintStatement(branch.body.get(), "Body", inner_last); });
|
|
}
|
|
EmitChildren(std::move(branch_children));
|
|
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
// Else branch
|
|
if (node.else_body)
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Else Branch:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
PrintStatement(node.else_body->get(), "Body", true);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitForInStatement(ForInStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ForInStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Key", node.key, nullptr, is_last); });
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Value", node.value, nullptr, is_last); });
|
|
children.push_back([&](bool is_last) { PrintExpression(node.collection.get(), "Collection", is_last); });
|
|
if (node.body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitForToStatement(ForToStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ForToStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Counter", node.counter, nullptr, is_last); });
|
|
children.push_back([&](bool is_last) { PrintKeyValue("IsDownto", node.is_downto, is_last); });
|
|
children.push_back([&](bool is_last) { PrintExpression(node.start.get(), "Start", is_last); });
|
|
children.push_back([&](bool is_last) { PrintExpression(node.end.get(), "End", is_last); });
|
|
if (node.step)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintExpression(node.step.get(), "Step", is_last); });
|
|
}
|
|
if (node.body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitWhileStatement(WhileStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("WhileStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
children.push_back([&](bool is_last) { PrintExpression(node.condition.get(), "Condition", is_last); });
|
|
if (node.body)
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitRepeatStatement(RepeatStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("RepeatStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (!node.body.empty())
|
|
{
|
|
children.push_back([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Body:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
for (size_t i = 0; i < node.body.size(); ++i)
|
|
{
|
|
PrintStatement(node.body[i].get(), "", i == node.body.size() - 1);
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
children.push_back([&](bool is_last) { PrintExpression(node.condition.get(), "Condition", is_last); });
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitCaseStatement(CaseStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("CaseStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
children.push_back([&](bool is_last) { PrintExpression(node.discriminant.get(), "Discriminant", is_last); });
|
|
|
|
for (size_t i = 0; i < node.branches.size(); ++i)
|
|
{
|
|
const auto& branch = node.branches[i];
|
|
children.push_back([&, i](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Branch:", Color::Yellow);
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(is_last);
|
|
|
|
std::vector<std::function<void(bool)>> branch_children;
|
|
branch_children.push_back([&](bool inner_last) {
|
|
PrintIndent(inner_last);
|
|
PrintColored("Values:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(inner_last);
|
|
for (size_t j = 0; j < branch.values.size(); ++j)
|
|
{
|
|
PrintExpression(branch.values[j].get(), "", j == branch.values.size() - 1);
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
|
|
if (branch.body)
|
|
{
|
|
branch_children.push_back([&](bool inner_last) { PrintStatement(branch.body.get(), "Body", inner_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(branch_children));
|
|
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
if (node.else_body)
|
|
children.push_back([&](bool is_last) { PrintStatement(node.else_body->get(), "Else", is_last); });
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitTryStatement(TryStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("TryStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
if (node.try_body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.try_body.get(), "Try", is_last && !node.except_body); });
|
|
}
|
|
|
|
if (node.except_body)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintStatement(node.except_body.get(), "Except", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitBreakStatement(BreakStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("BreakStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitContinueStatement(ContinueStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ContinueStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitReturnStatement(ReturnStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ReturnStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
if (node.value)
|
|
{
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(true);
|
|
PrintExpression(node.value->get(), "", true);
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::VisitUsesStatement(UsesStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("UsesStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
is_last_child_stack_.push_back(true);
|
|
for (size_t i = 0; i < node.units.size(); ++i)
|
|
{
|
|
PrintIndent(i == node.units.size() - 1);
|
|
PrintColored("\"" + node.units[i].name + "\"", Color::Green);
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.units[i].location);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
is_last_child_stack_.pop_back();
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitMatrixIterationStatement(MatrixIterationStatement& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("MatrixIterationStatement", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
children.push_back([&](bool is_last) { PrintExpression(node.target.get(), "Target", is_last && !node.body); });
|
|
if (node.body)
|
|
children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 函数和声明 =====
|
|
|
|
void DebugPrinter::VisitFunctionDefinition(FunctionDefinition& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("FunctionDefinition: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
size_t child_count = (node.parameters.empty() ? 0 : 1);
|
|
if (node.return_type)
|
|
++child_count;
|
|
if (node.body)
|
|
++child_count;
|
|
// Overload is always printed
|
|
++child_count;
|
|
|
|
size_t child_index = 0;
|
|
auto emit_child = [&](auto&& fn) {
|
|
bool is_last_child = ++child_index == child_count;
|
|
fn(is_last_child);
|
|
};
|
|
|
|
IncreaseIndent();
|
|
|
|
if (!node.parameters.empty())
|
|
{
|
|
emit_child([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
PrintColored("Parameters:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.parameters.size(); ++i)
|
|
{
|
|
if (node.parameters[i])
|
|
{
|
|
PrintParameter(*node.parameters[i], i == node.parameters.size() - 1);
|
|
}
|
|
}
|
|
DecreaseIndent();
|
|
});
|
|
}
|
|
|
|
emit_child([&](bool is_last) {
|
|
PrintIndent(is_last);
|
|
std::string overload = node.is_overload ? "true" : "false";
|
|
PrintColored("Overload: " + overload, Color::Cyan);
|
|
os_ << "\n";
|
|
});
|
|
|
|
if (node.return_type)
|
|
{
|
|
emit_child([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.body)
|
|
{
|
|
emit_child([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); });
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitFunctionDeclaration(FunctionDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("FunctionDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
if (!node.parameters.empty())
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Parameters:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
for (size_t i = 0; i < node.parameters.size(); ++i)
|
|
{
|
|
if (node.parameters[i])
|
|
{
|
|
PrintParameter(*node.parameters[i], i == node.parameters.size() - 1);
|
|
}
|
|
}
|
|
DecreaseIndent();
|
|
}
|
|
|
|
if (node.return_type)
|
|
{
|
|
PrintKeyValue("ReturnType", node.return_type->name);
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitVarDeclaration(VarDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("VarDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.initializer)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "InitialValue", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitStaticDeclaration(StaticDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("StaticDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.initializer)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitGlobalDeclaration(GlobalDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("GlobalDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
|
|
if (node.initializer)
|
|
children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); });
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitConstDeclaration(ConstDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ConstDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
}
|
|
|
|
if (node.value)
|
|
{
|
|
children.push_back([&](bool is_last) { PrintExpression(node.value.get(), "Value", is_last); });
|
|
}
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitFieldDeclaration(FieldDeclaration& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("FieldDeclaration: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
std::vector<std::function<void(bool)>> children;
|
|
|
|
if (node.type)
|
|
children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); });
|
|
|
|
if (node.initializer)
|
|
children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); });
|
|
|
|
EmitChildren(std::move(children));
|
|
DecreaseIndent();
|
|
}
|
|
|
|
// ===== 条件编译 =====
|
|
|
|
void DebugPrinter::VisitCompilerDirective(CompilerDirective& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("CompilerDirective: ", Color::BrightCyan);
|
|
PrintColored("\"" + node.name + "\"", Color::Green);
|
|
|
|
if (node.switch_value)
|
|
{
|
|
os_ << " " << GetColor(Color::Magenta) << *node.switch_value << GetColor(Color::Reset);
|
|
}
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitConditionalBlock(ConditionalBlock& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ConditionalBlock: ", Color::BrightCyan);
|
|
PrintConditionalCompilationType(node.type);
|
|
os_ << " " << GetColor(Color::Green) << node.name << GetColor(Color::Reset);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
|
|
IncreaseIndent();
|
|
|
|
if (!node.consequence.empty())
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Consequence:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
PrintStatements(node.consequence);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
if (!node.alternative.empty())
|
|
{
|
|
PrintIndent();
|
|
PrintColored("Alternative:", Color::Yellow);
|
|
os_ << "\n";
|
|
IncreaseIndent();
|
|
PrintStatements(node.alternative);
|
|
DecreaseIndent();
|
|
}
|
|
|
|
DecreaseIndent();
|
|
}
|
|
|
|
void DebugPrinter::VisitConditionalDirective(ConditionalDirective& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("ConditionalDirective: ", Color::BrightCyan);
|
|
PrintConditionalCompilationType(node.type);
|
|
os_ << " " << GetColor(Color::Green) << node.name << GetColor(Color::Reset);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.location);
|
|
}
|
|
os_ << "\n";
|
|
}
|
|
|
|
void DebugPrinter::VisitTSLXBlock(TSLXBlock& node)
|
|
{
|
|
PrintIndent();
|
|
PrintColored("TSLXBlock", Color::BrightCyan);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os_ << " ";
|
|
PrintLocation(node.span);
|
|
}
|
|
os_ << "\n";
|
|
|
|
// TSLXBlock 的具体内容未定义,暂时只打印节点名称
|
|
}
|
|
|
|
// ===== 便捷函数实现 =====
|
|
|
|
std::string DebugString(const ASTNode* node, const PrintOptions& opts)
|
|
{
|
|
std::ostringstream oss;
|
|
DebugPrinter printer(oss, opts);
|
|
printer.Print(node);
|
|
return oss.str();
|
|
}
|
|
|
|
std::string DebugString(const ParseResult& result, const PrintOptions& opts)
|
|
{
|
|
std::ostringstream oss;
|
|
DebugPrinter printer(oss, opts);
|
|
printer.PrintParseResult(result);
|
|
return oss.str();
|
|
}
|
|
|
|
void DebugPrint(const ASTNode* node, const PrintOptions& opts)
|
|
{
|
|
DebugPrinter printer(std::cout, opts);
|
|
printer.Print(node);
|
|
}
|
|
|
|
void DebugPrint(const ParseResult& result, const PrintOptions& opts)
|
|
{
|
|
DebugPrinter printer(std::cout, opts);
|
|
printer.PrintParseResult(result);
|
|
}
|
|
|
|
void DebugPrint(const ASTNode* node, const std::string& source, const PrintOptions& opts)
|
|
{
|
|
DebugPrinter printer(std::cout, opts);
|
|
printer.SetSourceCode(&source);
|
|
printer.Print(node);
|
|
}
|
|
|
|
void DebugPrint(const ParseResult& result, const std::string& source, const PrintOptions& opts)
|
|
{
|
|
DebugPrinter printer(std::cout, opts);
|
|
printer.SetSourceCode(&source);
|
|
printer.PrintParseResult(result);
|
|
}
|
|
}
|