feat(semantic): implement tree-based string representation for SymbolTable
Signed-off-by: erick-alcachofa <erick@artichoke.dev> - Add comprehensive toString() implementation for all symbol types. - Support recursive tree rendering for debugging symbol hierarchies. - Implement OverloadSet-based visitation for Symbol variants.
This commit is contained in:
parent
f235a72671
commit
d92f39538b
@ -185,4 +185,6 @@ namespace arti::lang::sym {
|
||||
Optional<TypeQualifier> qualifier;
|
||||
};
|
||||
|
||||
std::string toString(const SharedPtr<SymbolTable> &, const std::string &);
|
||||
|
||||
} // namespace arti::lang
|
||||
|
||||
800
lib/src/Semantics/SymbolTableToString.cpp
Normal file
800
lib/src/Semantics/SymbolTableToString.cpp
Normal file
@ -0,0 +1,800 @@
|
||||
//============================================================================//
|
||||
// //
|
||||
// artichoke programming language //
|
||||
// //
|
||||
// Copyright (C) 2025 Erick Saul Guzman Ramos, whoami.artichoke.dev //
|
||||
// //
|
||||
// //
|
||||
// This program is free software: you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU Affero General Public License as published //
|
||||
// by the Free Software Foundation, either version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU Affero General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU Affero General Public License //
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||
// //
|
||||
//============================================================================//
|
||||
|
||||
#include <artichoke/Semantics/SymbolTable.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <artichoke/Util/OverloadSet.hpp>
|
||||
|
||||
namespace arti::lang::sym {
|
||||
|
||||
constexpr std::string_view StrTreeNoNode = "│ ";
|
||||
constexpr std::string_view StrTreeChilds = "├─";
|
||||
constexpr std::string_view StrTreeLast = "└─";
|
||||
constexpr std::string_view StrTreeSpace = " ";
|
||||
|
||||
inline std::string nextPrefix(const std::string &prefix, bool isLast) {
|
||||
return prefix +
|
||||
(isLast ? std::string(StrTreeSpace) : std::string(StrTreeNoNode));
|
||||
}
|
||||
|
||||
std::string toString(const SymbolTable &, const std::string &);
|
||||
std::string toString(const SharedPtr<SymbolTable> &, const std::string &);
|
||||
std::string toString(const sym::Symbol &, const std::string &);
|
||||
std::string toString(const sym::Function &, const std::string &);
|
||||
std::string toString(const sym::FunctionType &, const std::string &);
|
||||
std::string toString(const sym::Enum &, const std::string &);
|
||||
std::string toString(const sym::EnumMember &, const std::string &);
|
||||
std::string toString(const sym::Struct &, const std::string &);
|
||||
std::string toString(const sym::StructMember &, const std::string &);
|
||||
std::string toString(const sym::TemplateParam &, const std::string &);
|
||||
std::string toString(const sym::TemplatedSymbol &, const std::string &);
|
||||
std::string toString(const sym::Variable &, const std::string &);
|
||||
std::string toString(const sym::Primitive &, const std::string &);
|
||||
std::string toString(const sym::TypeSymbol &, const std::string &);
|
||||
std::string
|
||||
toString(const SharedPtr<sym::FunctionType> &, const std::string &);
|
||||
|
||||
template <typename T>
|
||||
void appendItem(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
const T &item,
|
||||
bool isLastChild
|
||||
) {
|
||||
ss << "\n"
|
||||
<< prefix << (isLastChild ? StrTreeLast : StrTreeChilds) << " "
|
||||
<< toString(item, nextPrefix(prefix, isLastChild));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void appendGroupVec(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
std::string_view title,
|
||||
const std::vector<T> &items,
|
||||
bool isLastGroup
|
||||
) {
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
ss << "\n"
|
||||
<< prefix << (isLastGroup ? StrTreeLast : StrTreeChilds) << " " << title;
|
||||
for (std::size_t i = 0; i < items.size(); ++i) {
|
||||
appendItem(
|
||||
ss,
|
||||
nextPrefix(prefix, isLastGroup),
|
||||
items[i],
|
||||
i + 1 == items.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void appendGroupOne(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
std::string_view title,
|
||||
const T &item,
|
||||
bool isLastGroup
|
||||
) {
|
||||
ss << "\n"
|
||||
<< prefix << (isLastGroup ? StrTreeLast : StrTreeChilds) << " " << title;
|
||||
appendItem(ss, nextPrefix(prefix, isLastGroup), item, true);
|
||||
}
|
||||
|
||||
inline void appendGroupLeaf(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
std::string_view title,
|
||||
std::string_view value,
|
||||
bool isLastGroup
|
||||
) {
|
||||
ss << "\n"
|
||||
<< prefix << (isLastGroup ? StrTreeLast : StrTreeChilds) << " " << title;
|
||||
ss << "\n"
|
||||
<< nextPrefix(prefix, isLastGroup) << StrTreeLast << " `" << value
|
||||
<< "`";
|
||||
}
|
||||
|
||||
inline void appendGroupLeafList(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
std::string_view title,
|
||||
const std::vector<std::string> &values,
|
||||
bool isLastGroup
|
||||
) {
|
||||
if (values.empty()) {
|
||||
return;
|
||||
}
|
||||
ss << "\n"
|
||||
<< prefix << (isLastGroup ? StrTreeLast : StrTreeChilds) << " " << title;
|
||||
for (std::size_t i = 0; i < values.size(); ++i) {
|
||||
ss << "\n"
|
||||
<< nextPrefix(prefix, isLastGroup)
|
||||
<< (i + 1 == values.size() ? StrTreeLast : StrTreeChilds) << " `"
|
||||
<< values[i] << "`";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Map, typename Printer>
|
||||
void appendGroupHashMap(
|
||||
std::stringstream &ss,
|
||||
const std::string &prefix,
|
||||
std::string_view title,
|
||||
const Map &map,
|
||||
bool isLastGroup,
|
||||
Printer printer
|
||||
) {
|
||||
if (map.empty()) {
|
||||
return;
|
||||
}
|
||||
ss << "\n"
|
||||
<< prefix << (isLastGroup ? StrTreeLast : StrTreeChilds) << " " << title;
|
||||
const auto total = map.size();
|
||||
std::size_t index = 0;
|
||||
for (const auto &entry : map) {
|
||||
const auto &[key, value] = entry;
|
||||
const bool isLastEntry = ++index == total;
|
||||
const auto entryPrefix = nextPrefix(prefix, isLastGroup);
|
||||
ss << "\n"
|
||||
<< entryPrefix << (isLastEntry ? StrTreeLast : StrTreeChilds) << " `"
|
||||
<< key << "`";
|
||||
printer(ss, nextPrefix(entryPrefix, isLastEntry), value);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string formatName(const String &name) {
|
||||
return name.empty() ? std::string("<anonymous>") : std::string(name);
|
||||
}
|
||||
|
||||
inline std::string formatLocation(const SourceLocation &location) {
|
||||
return std::format("(line {}, col {})", location.line, location.column);
|
||||
}
|
||||
|
||||
inline std::string describeScope(const SymbolTable &table) {
|
||||
return std::format(
|
||||
"Scope `{}` {}",
|
||||
formatName(table.name),
|
||||
formatLocation(table.location)
|
||||
);
|
||||
}
|
||||
|
||||
inline std::string describeWeakScope(const WeakPtr<SymbolTable> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return describeScope(*locked);
|
||||
}
|
||||
return "<expired scope>";
|
||||
}
|
||||
|
||||
std::string describeWeakFunction(const WeakPtr<sym::Function> &);
|
||||
std::string describeWeakFunctionType(const WeakPtr<sym::FunctionType> &);
|
||||
std::string describeWeakStruct(const WeakPtr<sym::Struct> &);
|
||||
std::string describeWeakEnum(const WeakPtr<sym::Enum> &);
|
||||
std::string describeWeakPrimitive(const WeakPtr<sym::Primitive> &);
|
||||
std::string describeWeakTemplateParam(const WeakPtr<sym::TemplateParam> &);
|
||||
std::string describeWeakTypeSymbol(const WeakPtr<sym::TypeSymbol> &);
|
||||
std::string
|
||||
describeWeakTemplatedSymbol(const WeakPtr<sym::TemplatedSymbol> &);
|
||||
|
||||
inline std::string
|
||||
describeTemplatedSymbolTarget(const sym::WeakSymbol &symbol) {
|
||||
return std::visit(
|
||||
OverloadSet{
|
||||
[](const WeakPtr<sym::Function> &fn) {
|
||||
return describeWeakFunction(fn);
|
||||
},
|
||||
[](const WeakPtr<sym::Variable> &var) {
|
||||
if (auto locked = var.lock()) {
|
||||
return std::format("Variable `{}`", formatName(locked->name));
|
||||
}
|
||||
return std::string("<expired variable>");
|
||||
},
|
||||
[](const WeakPtr<sym::TypeSymbol> &) {
|
||||
return std::string("TypeSymbol");
|
||||
},
|
||||
[](const WeakPtr<sym::FunctionType> &fnType) {
|
||||
return describeWeakFunctionType(fnType);
|
||||
},
|
||||
[](const WeakPtr<sym::Primitive> &primitive) {
|
||||
return describeWeakPrimitive(primitive);
|
||||
},
|
||||
[](const WeakPtr<sym::Struct> &structure) {
|
||||
return describeWeakStruct(structure);
|
||||
},
|
||||
[](const WeakPtr<sym::Enum> &enumeration) {
|
||||
return describeWeakEnum(enumeration);
|
||||
},
|
||||
[](const WeakPtr<sym::TemplatedSymbol> &templated) {
|
||||
if (auto locked = templated.lock()) {
|
||||
return std::format(
|
||||
"TemplatedSymbol `{}`",
|
||||
formatName(locked->name)
|
||||
);
|
||||
}
|
||||
return std::string("<expired templated symbol>");
|
||||
} },
|
||||
symbol
|
||||
);
|
||||
}
|
||||
|
||||
inline std::string describeWeakFunction(const WeakPtr<sym::Function> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("Function `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired function>";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
describeWeakFunctionType(const WeakPtr<sym::FunctionType> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("FunctionType `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired function type>";
|
||||
}
|
||||
|
||||
inline std::string describeWeakStruct(const WeakPtr<sym::Struct> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("Struct `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired struct>";
|
||||
}
|
||||
|
||||
inline std::string describeWeakEnum(const WeakPtr<sym::Enum> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("Enum `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired enum>";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
describeWeakPrimitive(const WeakPtr<sym::Primitive> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("Primitive `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired primitive>";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
describeWeakTemplateParam(const WeakPtr<sym::TemplateParam> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("TemplateParam `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired template param>";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
describeWeakTemplatedSymbol(const WeakPtr<sym::TemplatedSymbol> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
return std::format("TemplatedSymbol `{}`", formatName(locked->name));
|
||||
}
|
||||
return "<expired template param>";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
describeWeakTypeSymbol(const WeakPtr<sym::TypeSymbol> &weak) {
|
||||
if (auto locked = weak.lock()) {
|
||||
(void) locked;
|
||||
return "TypeSymbol";
|
||||
}
|
||||
return "<expired type>";
|
||||
}
|
||||
|
||||
inline std::string qualifierName(TypeQualifier qualifier) {
|
||||
switch (qualifier) {
|
||||
case TypeQualifier::Uninitialized: return "Uninitialized";
|
||||
case TypeQualifier::Pointer: return "Pointer";
|
||||
case TypeQualifier::Slice: return "Slice";
|
||||
case TypeQualifier::Mutable: return "Mutable";
|
||||
case TypeQualifier::Optional: return "Optional";
|
||||
default: return "Unknown";
|
||||
}
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
std::string describeTypeKind(const sym::TypeSymbol::Type &type) {
|
||||
return std::visit(
|
||||
OverloadSet{
|
||||
[](const SharedPtr<sym::TypeSymbol> &nested) -> std::string {
|
||||
if (! nested) {
|
||||
return "<null type>";
|
||||
}
|
||||
return "TypeSymbol";
|
||||
},
|
||||
[](const WeakPtr<sym::FunctionType> &weak) -> std::string {
|
||||
return describeWeakFunctionType(weak);
|
||||
},
|
||||
[](const WeakPtr<sym::Primitive> &weak) -> std::string {
|
||||
return describeWeakPrimitive(weak);
|
||||
},
|
||||
[](const WeakPtr<sym::Struct> &weak) -> std::string {
|
||||
return describeWeakStruct(weak);
|
||||
},
|
||||
[](const WeakPtr<sym::Enum> &weak) -> std::string {
|
||||
return describeWeakEnum(weak);
|
||||
},
|
||||
[](const WeakPtr<sym::TemplatedSymbol> &weak) -> std::string {
|
||||
return describeWeakTemplatedSymbol(weak);
|
||||
},
|
||||
[](const WeakPtr<sym::TemplateParam> &weak) -> std::string {
|
||||
return describeWeakTemplateParam(weak);
|
||||
},
|
||||
},
|
||||
type
|
||||
);
|
||||
}
|
||||
|
||||
std::string toString(const SymbolTable &table, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << describeScope(table);
|
||||
|
||||
int groups = 0;
|
||||
if (! table.symbols.empty()) {
|
||||
++groups;
|
||||
}
|
||||
if (! table.inner.empty()) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (! table.symbols.empty()) {
|
||||
appendGroupHashMap(
|
||||
ss,
|
||||
prefix,
|
||||
"Symbols",
|
||||
table.symbols,
|
||||
++emitted == groups,
|
||||
[](
|
||||
std::stringstream &stream,
|
||||
const std::string &valuePrefix,
|
||||
const sym::Symbol &value
|
||||
) { appendItem(stream, valuePrefix, value, true); }
|
||||
);
|
||||
}
|
||||
if (! table.inner.empty()) {
|
||||
appendGroupHashMap(
|
||||
ss,
|
||||
prefix,
|
||||
"NestedScopes",
|
||||
table.inner,
|
||||
++emitted == groups,
|
||||
[](
|
||||
std::stringstream &stream,
|
||||
const std::string &valuePrefix,
|
||||
const SharedPtr<SymbolTable> &child
|
||||
) { appendItem(stream, valuePrefix, child, true); }
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const SharedPtr<SymbolTable> &ptr, const std::string &prefix) {
|
||||
if (! ptr) {
|
||||
return "<null scope>";
|
||||
}
|
||||
return toString(*ptr, prefix);
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const SharedPtr<sym::FunctionType> &ptr, const std::string &prefix) {
|
||||
if (! ptr) {
|
||||
return "<null function type>";
|
||||
}
|
||||
return toString(*ptr, prefix);
|
||||
}
|
||||
|
||||
std::string toString(const sym::Symbol &symbol, const std::string &prefix) {
|
||||
return std::visit(
|
||||
OverloadSet{
|
||||
[&prefix](const SharedPtr<sym::Function> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null function>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::Variable> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null variable>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::TypeSymbol> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null type symbol>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::FunctionType> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null function type>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::Primitive> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null primitive>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::Struct> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null struct>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::Enum> &value) -> std::string {
|
||||
return value ? toString(*value, prefix) : std::string("<null enum>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::TemplatedSymbol> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null templated symbol>");
|
||||
},
|
||||
[&prefix](const SharedPtr<sym::TemplateParam> &value) -> std::string {
|
||||
return value ? toString(*value, prefix)
|
||||
: std::string("<null templated symbol>");
|
||||
},
|
||||
},
|
||||
symbol
|
||||
);
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::TemplatedSymbol &templated, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"TemplatedSymbol `{}` {}",
|
||||
formatName(templated.name),
|
||||
formatLocation(templated.location)
|
||||
);
|
||||
|
||||
int groups = 0;
|
||||
if (! templated.symbol.valueless_by_exception()) {
|
||||
++groups;
|
||||
}
|
||||
if (! templated.params.empty()) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (! templated.symbol.valueless_by_exception()) {
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"BaseSymbol",
|
||||
describeTemplatedSymbolTarget(templated.symbol),
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
if (! templated.params.empty()) {
|
||||
appendGroupVec(
|
||||
ss,
|
||||
prefix,
|
||||
"Params",
|
||||
templated.params,
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(const sym::Function &fn, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"Function `{}` {}",
|
||||
formatName(fn.name),
|
||||
formatLocation(fn.location)
|
||||
);
|
||||
|
||||
int groups = 0;
|
||||
if (fn.body) {
|
||||
++groups;
|
||||
}
|
||||
auto typePtr = fn.type.lock();
|
||||
const bool hasType = static_cast<bool>(typePtr);
|
||||
if (hasType) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (fn.body) {
|
||||
appendGroupOne(ss, prefix, "Body", fn.body, ++emitted == groups);
|
||||
}
|
||||
if (hasType) {
|
||||
appendGroupOne(ss, prefix, "Type", typePtr, ++emitted == groups);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::FunctionType &fnType, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"FunctionType `{}` {}",
|
||||
formatName(fnType.name),
|
||||
formatLocation(fnType.location)
|
||||
);
|
||||
|
||||
int groups = 0;
|
||||
if (! fnType.symbol.expired()) {
|
||||
++groups;
|
||||
}
|
||||
if (! fnType.arguments.empty()) {
|
||||
++groups;
|
||||
}
|
||||
if (fnType.returnType) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (! fnType.symbol.expired()) {
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Symbol",
|
||||
describeWeakFunction(fnType.symbol),
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
if (! fnType.arguments.empty()) {
|
||||
std::vector<std::string> arguments;
|
||||
arguments.reserve(fnType.arguments.size());
|
||||
for (const auto &argument : fnType.arguments) {
|
||||
arguments.emplace_back(describeWeakTypeSymbol(argument));
|
||||
}
|
||||
appendGroupLeafList(
|
||||
ss,
|
||||
prefix,
|
||||
"Arguments",
|
||||
arguments,
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
if (fnType.returnType) {
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Return",
|
||||
describeWeakTypeSymbol(*fnType.returnType),
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::Enum &enumeration, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"Enum `{}` {} size={} align={}",
|
||||
formatName(enumeration.name),
|
||||
formatLocation(enumeration.location),
|
||||
enumeration.size,
|
||||
enumeration.alignment
|
||||
);
|
||||
|
||||
int groups = 0;
|
||||
if (! enumeration.membersList.empty()) {
|
||||
++groups;
|
||||
}
|
||||
if (! enumeration.methods.empty()) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (! enumeration.membersList.empty()) {
|
||||
appendGroupVec(
|
||||
ss,
|
||||
prefix,
|
||||
"Members",
|
||||
enumeration.membersList,
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
if (! enumeration.methods.empty()) {
|
||||
appendGroupHashMap(
|
||||
ss,
|
||||
prefix,
|
||||
"Methods",
|
||||
enumeration.methods,
|
||||
++emitted == groups,
|
||||
[](
|
||||
std::stringstream &stream,
|
||||
const std::string &valuePrefix,
|
||||
const WeakPtr<sym::Function> &method
|
||||
) {
|
||||
appendGroupLeaf(
|
||||
stream,
|
||||
valuePrefix,
|
||||
"Function",
|
||||
describeWeakFunction(method),
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::EnumMember &member, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"EnumMember `{}` {} index={}",
|
||||
formatName(member.name),
|
||||
formatLocation(member.location),
|
||||
member.index
|
||||
);
|
||||
if (member.type) {
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Type",
|
||||
describeWeakTypeSymbol(*member.type),
|
||||
true
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::Struct &structure, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"Struct `{}` {} size={} align={}",
|
||||
formatName(structure.name),
|
||||
formatLocation(structure.location),
|
||||
structure.size,
|
||||
structure.alignment
|
||||
);
|
||||
|
||||
int groups = 0;
|
||||
if (! structure.membersList.empty()) {
|
||||
++groups;
|
||||
}
|
||||
if (! structure.methods.empty()) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
if (! structure.membersList.empty()) {
|
||||
appendGroupVec(
|
||||
ss,
|
||||
prefix,
|
||||
"Members",
|
||||
structure.membersList,
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
if (! structure.methods.empty()) {
|
||||
appendGroupHashMap(
|
||||
ss,
|
||||
prefix,
|
||||
"Methods",
|
||||
structure.methods,
|
||||
++emitted == groups,
|
||||
[](
|
||||
std::stringstream &stream,
|
||||
const std::string &valuePrefix,
|
||||
const WeakPtr<sym::Function> &method
|
||||
) {
|
||||
appendGroupLeaf(
|
||||
stream,
|
||||
valuePrefix,
|
||||
"Function",
|
||||
describeWeakFunction(method),
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::StructMember &member, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"StructMember `{}` {} index={} offset={}",
|
||||
formatName(member.name),
|
||||
formatLocation(member.location),
|
||||
member.index,
|
||||
member.offset
|
||||
);
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Type",
|
||||
describeWeakTypeSymbol(member.type),
|
||||
true
|
||||
);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(const sym::TemplateParam ¶m, const std::string &) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"TemplateParam `{}` {}",
|
||||
formatName(param.name),
|
||||
formatLocation(param.location)
|
||||
);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(const sym::Variable &var, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"Variable `{}` {}",
|
||||
formatName(var.name),
|
||||
formatLocation(var.location)
|
||||
);
|
||||
appendGroupLeaf(ss, prefix, "Type", describeWeakTypeSymbol(var.type), true);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(const sym::Primitive &primitive, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << std::format(
|
||||
"Primitive `{}` size={} align={}",
|
||||
formatName(primitive.name),
|
||||
primitive.size,
|
||||
primitive.alignment
|
||||
);
|
||||
(void) prefix;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(const sym::TypeSymbol &type, const std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << "TypeSymbol";
|
||||
|
||||
int groups = 1;
|
||||
if (type.qualifier) {
|
||||
++groups;
|
||||
}
|
||||
|
||||
int emitted = 0;
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Kind",
|
||||
describeTypeKind(type.type),
|
||||
++emitted == groups
|
||||
);
|
||||
if (type.qualifier) {
|
||||
appendGroupLeaf(
|
||||
ss,
|
||||
prefix,
|
||||
"Qualifier",
|
||||
qualifierName(*type.qualifier),
|
||||
++emitted == groups
|
||||
);
|
||||
}
|
||||
return ss.str();
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string toPrettyString(const SymbolTable &table, std::string prefix) {
|
||||
auto rendered = toString(table, prefix);
|
||||
if (! prefix.empty()) {
|
||||
rendered.insert(0, prefix);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
} // namespace arti::lang::sym
|
||||
Loading…
x
Reference in New Issue
Block a user