// Copyright (C) 2020-2023 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC 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 General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// .
#include "rust-ast-dump.h"
namespace Rust {
namespace AST {
Indent::Indent () : tabs (0) {}
std::ostream &
operator<< (std::ostream &stream, const Indent &indent)
{
return stream << std::string (indent.tabs, '\t');
}
void
Indent::increment ()
{
tabs++;
}
void
Indent::decrement ()
{
rust_assert (tabs != 0);
tabs--;
}
Dump::Dump (std::ostream &stream) : stream (stream), indentation (Indent ()) {}
void
Dump::go (AST::Crate &crate)
{
for (auto &item : crate.items)
{
stream << indentation;
item->accept_vis (*this);
stream << "\n";
}
}
void
Dump::go (AST::Item &item)
{
item.accept_vis (*this);
}
void
Dump::format_function_param (FunctionParam ¶m)
{
param.get_pattern ()->accept_vis (*this);
stream << ": ";
param.get_type ()->accept_vis (*this);
}
void
Dump::emit_attrib (const Attribute &attrib)
{
stream << "#";
stream << "[";
for (size_t i = 0; i < attrib.get_path ().get_segments ().size (); i++)
{
const auto &seg = attrib.get_path ().get_segments ().at (i);
bool has_next = (i + 1) < attrib.get_path ().get_segments ().size ();
stream << seg.get_segment_name ();
if (has_next)
stream << "::";
}
if (attrib.has_attr_input ())
{
stream << " = ";
bool is_literal = attrib.get_attr_input ().get_attr_input_type ()
== AST::AttrInput::AttrInputType::LITERAL;
if (is_literal)
{
auto &literal
= static_cast (attrib.get_attr_input ());
const auto &value = literal.get_literal ().as_string ();
stream << "\"" << value << "\"";
}
else
{
stream << "FIXME";
}
}
stream << "]";
}
void
Dump::visit (Token &tok)
{}
void
Dump::visit (DelimTokenTree &delim_tok_tree)
{}
void
Dump::visit (AttrInputMetaItemContainer &input)
{}
void
Dump::visit (IdentifierExpr &ident_expr)
{
stream << ident_expr.get_ident ();
}
void
Dump::visit (Lifetime &lifetime)
{}
void
Dump::visit (LifetimeParam &lifetime_param)
{}
void
Dump::visit (ConstGenericParam &lifetime_param)
{}
// rust-path.h
void
Dump::visit (PathInExpression &path)
{}
void
Dump::visit (TypePathSegment &segment)
{}
void
Dump::visit (TypePathSegmentGeneric &segment)
{}
void
Dump::visit (TypePathSegmentFunction &segment)
{}
void
Dump::visit (TypePath &path)
{
stream << path.as_string ();
}
void
Dump::visit (QualifiedPathInExpression &path)
{}
void
Dump::visit (QualifiedPathInType &path)
{}
// rust-expr.h
void
Dump::visit (LiteralExpr &expr)
{
stream << expr.as_string ();
}
void
Dump::visit (AttrInputLiteral &attr_input)
{}
void
Dump::visit (MetaItemLitExpr &meta_item)
{}
void
Dump::visit (MetaItemPathLit &meta_item)
{}
void
Dump::visit (BorrowExpr &expr)
{}
void
Dump::visit (DereferenceExpr &expr)
{}
void
Dump::visit (ErrorPropagationExpr &expr)
{}
void
Dump::visit (NegationExpr &expr)
{}
void
Dump::visit (ArithmeticOrLogicalExpr &expr)
{
expr.get_left_expr ()->accept_vis (*this);
stream << " ";
switch (expr.get_expr_type ())
{
case ArithmeticOrLogicalOperator::ADD:
stream << "+";
break;
case ArithmeticOrLogicalOperator::SUBTRACT:
stream << "-";
break;
case ArithmeticOrLogicalOperator::MULTIPLY:
stream << "*";
break;
case ArithmeticOrLogicalOperator::DIVIDE:
stream << "/";
break;
case ArithmeticOrLogicalOperator::MODULUS:
stream << "%";
break;
case ArithmeticOrLogicalOperator::BITWISE_AND:
stream << "&";
break;
case ArithmeticOrLogicalOperator::BITWISE_OR:
stream << "|";
break;
case ArithmeticOrLogicalOperator::BITWISE_XOR:
stream << "^";
break;
case ArithmeticOrLogicalOperator::LEFT_SHIFT:
stream << "<<";
break;
case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
stream << ">>";
break;
}
stream << " ";
expr.get_right_expr ()->accept_vis (*this);
}
void
Dump::visit (ComparisonExpr &expr)
{}
void
Dump::visit (LazyBooleanExpr &expr)
{}
void
Dump::visit (TypeCastExpr &expr)
{}
void
Dump::visit (AssignmentExpr &expr)
{}
void
Dump::visit (CompoundAssignmentExpr &expr)
{}
void
Dump::visit (GroupedExpr &expr)
{}
void
Dump::visit (ArrayElemsValues &elems)
{}
void
Dump::visit (ArrayElemsCopied &elems)
{}
void
Dump::visit (ArrayExpr &expr)
{}
void
Dump::visit (ArrayIndexExpr &expr)
{}
void
Dump::visit (TupleExpr &expr)
{}
void
Dump::visit (TupleIndexExpr &expr)
{}
void
Dump::visit (StructExprStruct &expr)
{}
void
Dump::visit (StructExprFieldIdentifier &field)
{}
void
Dump::visit (StructExprFieldIdentifierValue &field)
{}
void
Dump::visit (StructExprFieldIndexValue &field)
{}
void
Dump::visit (StructExprStructFields &expr)
{}
void
Dump::visit (StructExprStructBase &expr)
{}
void
Dump::visit (CallExpr &expr)
{}
void
Dump::visit (MethodCallExpr &expr)
{}
void
Dump::visit (FieldAccessExpr &expr)
{}
void
Dump::visit (ClosureExprInner &expr)
{}
void
Dump::visit (BlockExpr &expr)
{
stream << "{\n";
indentation.increment ();
for (auto &stmt : expr.get_statements ())
{
stream << indentation;
stmt->accept_vis (*this);
stream << ";\n";
}
if (expr.has_tail_expr ())
{
stream << indentation;
expr.get_tail_expr ()->accept_vis (*this);
}
indentation.decrement ();
stream << "\n" << indentation << "}\n";
}
void
Dump::visit (ClosureExprInnerTyped &expr)
{}
void
Dump::visit (ContinueExpr &expr)
{}
void
Dump::visit (BreakExpr &expr)
{}
void
Dump::visit (RangeFromToExpr &expr)
{}
void
Dump::visit (RangeFromExpr &expr)
{}
void
Dump::visit (RangeToExpr &expr)
{}
void
Dump::visit (RangeFullExpr &expr)
{}
void
Dump::visit (RangeFromToInclExpr &expr)
{}
void
Dump::visit (RangeToInclExpr &expr)
{}
void
Dump::visit (ReturnExpr &expr)
{}
void
Dump::visit (UnsafeBlockExpr &expr)
{}
void
Dump::visit (LoopExpr &expr)
{}
void
Dump::visit (WhileLoopExpr &expr)
{}
void
Dump::visit (WhileLetLoopExpr &expr)
{}
void
Dump::visit (ForLoopExpr &expr)
{}
void
Dump::visit (IfExpr &expr)
{}
void
Dump::visit (IfExprConseqElse &expr)
{}
void
Dump::visit (IfExprConseqIf &expr)
{}
void
Dump::visit (IfExprConseqIfLet &expr)
{}
void
Dump::visit (IfLetExpr &expr)
{}
void
Dump::visit (IfLetExprConseqElse &expr)
{}
void
Dump::visit (IfLetExprConseqIf &expr)
{}
void
Dump::visit (IfLetExprConseqIfLet &expr)
{}
void
Dump::visit (MatchExpr &expr)
{}
void
Dump::visit (AwaitExpr &expr)
{}
void
Dump::visit (AsyncBlockExpr &expr)
{}
// rust-item.h
void
Dump::visit (TypeParam ¶m)
{
stream << param.get_type_representation ();
if (param.has_type ())
{
stream << " = ";
param.get_type ()->accept_vis (*this);
}
}
void
Dump::visit (LifetimeWhereClauseItem &item)
{}
void
Dump::visit (TypeBoundWhereClauseItem &item)
{}
void
Dump::visit (Method &method)
{
stream << indentation << "fn " << method.get_method_name () << '(';
auto &self = method.get_self_param ();
stream << self.as_string ();
auto ¶ms = method.get_function_params ();
for (auto ¶m : params)
{
stream << ", ";
format_function_param (param);
}
stream << ") ";
if (method.has_return_type ())
{
stream << "-> ";
method.get_return_type ()->accept_vis (*this);
stream << " ";
}
auto &block = method.get_definition ();
if (!block)
stream << ';';
else
block->accept_vis (*this);
stream << '\n';
}
void
Dump::visit (Module &module)
{}
void
Dump::visit (ExternCrate &crate)
{}
void
Dump::visit (UseTreeGlob &use_tree)
{}
void
Dump::visit (UseTreeList &use_tree)
{}
void
Dump::visit (UseTreeRebind &use_tree)
{}
void
Dump::visit (UseDeclaration &use_decl)
{}
void
Dump::visit (Function &function)
{
stream << "fn " << function.get_function_name ();
if (function.has_generics ())
{
stream << "<";
for (size_t i = 0; i < function.get_generic_params ().size (); i++)
{
auto ¶m = function.get_generic_params ().at (i);
param->accept_vis (*this);
bool has_next = (i + 1) < function.get_generic_params ().size ();
if (has_next)
stream << ", ";
}
stream << ">";
}
stream << '(';
auto ¶ms = function.get_function_params ();
if (params.size () >= 1)
{
format_function_param (params[0]);
for (size_t i = 1; i < params.size (); i++)
{
stream << ", ";
format_function_param (params[i]);
}
}
stream << ") ";
if (function.has_return_type ())
{
stream << "-> ";
function.get_return_type ()->accept_vis (*this);
stream << " ";
}
auto &block = function.get_definition ();
if (!block)
stream << ';';
else
block->accept_vis (*this);
stream << '\n';
}
void
Dump::visit (TypeAlias &type_alias)
{}
void
Dump::visit (StructStruct &struct_item)
{}
void
Dump::visit (TupleStruct &tuple_struct)
{}
void
Dump::visit (EnumItem &item)
{}
void
Dump::visit (EnumItemTuple &item)
{}
void
Dump::visit (EnumItemStruct &item)
{}
void
Dump::visit (EnumItemDiscriminant &item)
{}
void
Dump::visit (Enum &enum_item)
{}
void
Dump::visit (Union &union_item)
{}
void
Dump::visit (ConstantItem &const_item)
{}
void
Dump::visit (StaticItem &static_item)
{}
void
Dump::format_function_common (std::unique_ptr &return_type,
std::unique_ptr &block)
{
if (return_type)
{
stream << "-> ";
return_type->accept_vis (*this);
}
if (block)
{
if (return_type)
stream << ' ';
block->accept_vis (*this);
}
else
stream << ";\n";
}
void
Dump::visit (TraitItemFunc &item)
{
auto func = item.get_trait_function_decl ();
stream << indentation << "fn " << func.get_identifier () << '(';
auto ¶ms = func.get_function_params ();
for (auto ¶m : params)
{
stream << ", ";
format_function_param (param);
}
stream << ") ";
format_function_common (func.get_return_type (), item.get_definition ());
}
void
Dump::visit (TraitItemMethod &item)
{
auto method = item.get_trait_method_decl ();
stream << indentation << "fn " << method.get_identifier () << '(';
auto &self = method.get_self_param ();
stream << self.as_string ();
auto ¶ms = method.get_function_params ();
for (auto ¶m : params)
{
stream << ", ";
format_function_param (param);
}
stream << ") ";
format_function_common (method.get_return_type (), item.get_definition ());
}
void
Dump::visit (TraitItemConst &item)
{
stream << indentation << "const " << item.get_identifier () << ": ";
item.get_type ()->accept_vis (*this);
stream << ";\n";
}
void
Dump::visit (TraitItemType &item)
{
stream << indentation << "type " << item.get_identifier () << ";\n";
}
void
Dump::visit (Trait &trait)
{
for (const auto &attr : trait.get_outer_attrs ())
{
emit_attrib (attr);
stream << "\n" << indentation;
}
stream << "trait " << trait.get_identifier ();
// Traits actually have an implicit Self thrown at the start so we must expect
// the number of generic params to be > 1
if (trait.get_generic_params ().size () > 1)
{
stream << "<";
for (size_t i = 1; i < trait.get_generic_params ().size (); i++)
{
auto ¶m = trait.get_generic_params ().at (i);
param->accept_vis (*this);
bool has_next = (i + 1) < trait.get_generic_params ().size ();
if (has_next)
stream << ", ";
}
stream << ">";
}
stream << " {\n";
indentation.increment ();
for (auto &item : trait.get_trait_items ())
item->accept_vis (*this);
indentation.decrement ();
stream << "\n}\n";
}
void
Dump::visit (InherentImpl &impl)
{
stream << "impl ";
// FIXME: Handle generics
impl.get_type ()->accept_vis (*this);
// FIXME: Handle where-clause
// FIXME: Handle inner attributes
stream << " {\n";
indentation.increment ();
for (auto &item : impl.get_impl_items ())
item->accept_vis (*this);
indentation.decrement ();
stream << "\n}\n";
}
void
Dump::visit (TraitImpl &impl)
{
stream << "impl ";
impl.get_trait_path ().accept_vis (*this);
stream << " for ";
impl.get_type ()->accept_vis (*this);
stream << " {\n";
indentation.increment ();
for (auto &item : impl.get_impl_items ())
item->accept_vis (*this);
indentation.decrement ();
stream << "\n}\n";
}
void
Dump::visit (ExternalStaticItem &item)
{}
void
Dump::visit (ExternalFunctionItem &function)
{
stream << "fn " << function.get_identifier () << '(';
for (size_t i = 0; i < function.get_function_params ().size (); i++)
{
auto ¶m = function.get_function_params ().at (i);
bool has_next = (i + 1) < function.get_function_params ().size ();
stream << param.get_name () << ": ";
param.get_type ()->accept_vis (*this);
if (has_next)
stream << ", ";
}
stream << ')';
if (function.has_return_type ())
{
stream << "-> ";
function.get_return_type ()->accept_vis (*this);
}
}
void
Dump::visit (ExternBlock &block)
{
stream << "extern ";
if (block.has_abi ())
{
stream << "\"";
stream << block.get_abi ();
stream << "\" ";
}
stream << "{\n";
indentation.increment ();
for (auto &item : block.get_extern_items ())
{
stream << indentation;
item->accept_vis (*this);
stream << ";\n";
}
indentation.decrement ();
stream << "\n" << indentation << "}\n";
}
// rust-macro.h
void
Dump::visit (MacroMatchFragment &match)
{}
void
Dump::visit (MacroMatchRepetition &match)
{}
void
Dump::visit (MacroMatcher &matcher)
{}
void
Dump::visit (MacroRulesDefinition &rules_def)
{}
void
Dump::visit (MacroInvocation ¯o_invoc)
{}
void
Dump::visit (MetaItemPath &meta_item)
{}
void
Dump::visit (MetaItemSeq &meta_item)
{}
void
Dump::visit (MetaWord &meta_item)
{}
void
Dump::visit (MetaNameValueStr &meta_item)
{}
void
Dump::visit (MetaListPaths &meta_item)
{}
void
Dump::visit (MetaListNameValueStr &meta_item)
{}
// rust-pattern.h
void
Dump::visit (LiteralPattern &pattern)
{}
void
Dump::visit (IdentifierPattern &pattern)
{
stream << pattern.get_ident ();
}
void
Dump::visit (WildcardPattern &pattern)
{}
// void Dump::visit(RangePatternBound& bound){}
void
Dump::visit (RangePatternBoundLiteral &bound)
{}
void
Dump::visit (RangePatternBoundPath &bound)
{}
void
Dump::visit (RangePatternBoundQualPath &bound)
{}
void
Dump::visit (RangePattern &pattern)
{}
void
Dump::visit (ReferencePattern &pattern)
{}
// void Dump::visit(StructPatternField& field){}
void
Dump::visit (StructPatternFieldTuplePat &field)
{}
void
Dump::visit (StructPatternFieldIdentPat &field)
{}
void
Dump::visit (StructPatternFieldIdent &field)
{}
void
Dump::visit (StructPattern &pattern)
{}
// void Dump::visit(TupleStructItems& tuple_items){}
void
Dump::visit (TupleStructItemsNoRange &tuple_items)
{}
void
Dump::visit (TupleStructItemsRange &tuple_items)
{}
void
Dump::visit (TupleStructPattern &pattern)
{}
// void Dump::visit(TuplePatternItems& tuple_items){}
void
Dump::visit (TuplePatternItemsMultiple &tuple_items)
{}
void
Dump::visit (TuplePatternItemsRanged &tuple_items)
{}
void
Dump::visit (TuplePattern &pattern)
{}
void
Dump::visit (GroupedPattern &pattern)
{}
void
Dump::visit (SlicePattern &pattern)
{}
// rust-stmt.h
void
Dump::visit (EmptyStmt &stmt)
{}
void
Dump::visit (LetStmt &stmt)
{
stream << "let ";
auto &pattern = stmt.get_pattern ();
if (pattern)
pattern->accept_vis (*this);
if (stmt.has_type ())
{
stream << ": ";
stmt.get_type ()->accept_vis (*this);
}
if (stmt.has_init_expr ())
{
stream << " = ";
stmt.get_init_expr ()->accept_vis (*this);
}
}
void
Dump::visit (ExprStmtWithoutBlock &stmt)
{}
void
Dump::visit (ExprStmtWithBlock &stmt)
{}
// rust-type.h
void
Dump::visit (TraitBound &bound)
{}
void
Dump::visit (ImplTraitType &type)
{}
void
Dump::visit (TraitObjectType &type)
{}
void
Dump::visit (ParenthesisedType &type)
{}
void
Dump::visit (ImplTraitTypeOneBound &type)
{}
void
Dump::visit (TraitObjectTypeOneBound &type)
{}
void
Dump::visit (TupleType &type)
{}
void
Dump::visit (NeverType &type)
{}
void
Dump::visit (RawPointerType &type)
{}
void
Dump::visit (ReferenceType &type)
{
type.get_type_referenced ()->accept_vis (*this);
}
void
Dump::visit (ArrayType &type)
{
type.get_elem_type ()->accept_vis (*this);
}
void
Dump::visit (SliceType &type)
{
type.get_elem_type ()->accept_vis (*this);
}
void
Dump::visit (InferredType &type)
{
stream << "_";
}
void
Dump::visit (BareFunctionType &type)
{}
} // namespace AST
} // namespace Rust