diff mbox series

[049/125] gccrs: format-args: Add basic expansion of unnamed Display::fmt arguments.

Message ID 20240801145809.366388-51-arthur.cohen@embecosm.com
State New
Headers show
Series [001/125] Rust: Make 'tree'-level 'MAIN_NAME_P' work | expand

Commit Message

Arthur Cohen Aug. 1, 2024, 2:56 p.m. UTC
gcc/rust/ChangeLog:

	* ast/rust-ast-builder.h: Rename AST::AstBuilder -> AST::Builder
	* ast/rust-ast-builder.cc: Likewise.
	* expand/rust-derive.cc: Use new AST::Builder name.
	* expand/rust-derive.h: Likewise.
	* ast/rust-builtin-ast-nodes.h: Add required getters.
	* expand/rust-expand-format-args.cc (format_arg): New.
	(get_trait_name): New.
	(expand_format_args): Properly expand basic format_args!() invocations.
	* expand/rust-expand-format-args.h (expand_format_args): Fix signature.
	* expand/rust-macro-builtins.cc (MacroBuiltin::format_args_handler):
	Call into expand_format_args().
---
 gcc/rust/ast/rust-ast-builder.cc           |  66 ++++++++-----
 gcc/rust/ast/rust-ast-builder.h            |  51 ++++++----
 gcc/rust/ast/rust-builtin-ast-nodes.h      |   5 +
 gcc/rust/expand/rust-derive.cc             |   2 +-
 gcc/rust/expand/rust-derive.h              |   2 +-
 gcc/rust/expand/rust-expand-format-args.cc | 107 +++++++++++++++++++--
 gcc/rust/expand/rust-expand-format-args.h  |   5 +-
 gcc/rust/expand/rust-macro-builtins.cc     |  23 +++--
 8 files changed, 205 insertions(+), 56 deletions(-)
diff mbox series

Patch

diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc
index 0d5218c6381..1138d3dc2b2 100644
--- a/gcc/rust/ast/rust-ast-builder.cc
+++ b/gcc/rust/ast/rust-ast-builder.cc
@@ -17,53 +17,73 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-ast-builder.h"
+#include "rust-ast-full-decls.h"
 #include "rust-ast-full.h"
+#include "rust-expr.h"
+#include "rust-token.h"
+#include "rust-make-unique.h"
 
 namespace Rust {
 namespace AST {
 
 std::unique_ptr<Expr>
-AstBuilder::call (std::unique_ptr<Expr> &&path,
-		  std::vector<std::unique_ptr<Expr>> &&args)
+Builder::literal_string (std::string &&content) const
+{
+  return std::unique_ptr<Expr> (
+    new AST::LiteralExpr (std::move (content), Literal::LitType::STRING,
+			  PrimitiveCoreType::CORETYPE_STR, {}, loc));
+}
+
+std::unique_ptr<Expr>
+Builder::call (std::unique_ptr<Expr> &&path,
+	       std::vector<std::unique_ptr<Expr>> &&args) const
 {
   return std::unique_ptr<Expr> (
     new CallExpr (std::move (path), std::move (args), {}, loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::identifier (std::string name)
+Builder::array (std::vector<std::unique_ptr<Expr>> &&members) const
+{
+  auto elts = Rust::make_unique<ArrayElemsValues> (std::move (members), loc);
+
+  return std::unique_ptr<Expr> (new ArrayExpr (std::move (elts), {}, {}, loc));
+}
+
+std::unique_ptr<Expr>
+Builder::identifier (std::string name) const
 {
   return std::unique_ptr<Expr> (new IdentifierExpr (name, {}, loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::tuple_idx (std::string receiver, int idx)
+Builder::tuple_idx (std::string receiver, int idx) const
 {
   return std::unique_ptr<Expr> (
     new TupleIndexExpr (identifier (receiver), idx, {}, loc));
 }
 
 FunctionQualifiers
-AstBuilder::fn_qualifiers ()
+Builder::fn_qualifiers () const
 {
   return FunctionQualifiers (loc, Async::No, Const::No, Unsafety::Normal);
 }
 
 PathExprSegment
-AstBuilder::path_segment (std::string seg)
+Builder::path_segment (std::string seg) const
 {
   return PathExprSegment (PathIdentSegment (seg, loc), loc);
 }
 
 std::unique_ptr<TypePathSegment>
-AstBuilder::type_path_segment (std::string seg)
+Builder::type_path_segment (std::string seg) const
 {
   return std::unique_ptr<TypePathSegment> (
     new TypePathSegment (seg, false, loc));
 }
 
 std::unique_ptr<Type>
-AstBuilder::single_type_path (std::string type)
+Builder::single_type_path (std::string type) const
 {
   auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
   segments.emplace_back (type_path_segment (type));
@@ -72,7 +92,7 @@  AstBuilder::single_type_path (std::string type)
 }
 
 PathInExpression
-AstBuilder::path_in_expression (std::vector<std::string> &&segments)
+Builder::path_in_expression (std::vector<std::string> &&segments) const
 {
   auto path_segments = std::vector<PathExprSegment> ();
   for (auto &seg : segments)
@@ -82,8 +102,8 @@  AstBuilder::path_in_expression (std::vector<std::string> &&segments)
 }
 
 std::unique_ptr<Expr>
-AstBuilder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
-		   std::unique_ptr<Expr> &&tail_expr)
+Builder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
+		std::unique_ptr<Expr> &&tail_expr) const
 {
   return std::unique_ptr<Expr> (new BlockExpr (std::move (stmts),
 					       std::move (tail_expr), {}, {},
@@ -91,8 +111,8 @@  AstBuilder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
 }
 
 std::unique_ptr<Stmt>
-AstBuilder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
-		 std::unique_ptr<Expr> init)
+Builder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
+	      std::unique_ptr<Expr> init) const
 {
   return std::unique_ptr<Stmt> (new LetStmt (std::move (pattern),
 					     std::move (init), std::move (type),
@@ -100,28 +120,29 @@  AstBuilder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
 }
 
 std::unique_ptr<Expr>
-AstBuilder::ref (std::unique_ptr<Expr> &&of, bool mut)
+Builder::ref (std::unique_ptr<Expr> &&of, bool mut) const
 {
   return std::unique_ptr<Expr> (
     new BorrowExpr (std::move (of), mut, /* is double */ false, {}, loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::deref (std::unique_ptr<Expr> &&of)
+Builder::deref (std::unique_ptr<Expr> &&of) const
 {
   return std::unique_ptr<Expr> (new DereferenceExpr (std::move (of), {}, loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::struct_expr_struct (std::string struct_name)
+Builder::struct_expr_struct (std::string struct_name) const
 {
   return std::unique_ptr<Expr> (
     new StructExprStruct (path_in_expression ({struct_name}), {}, {}, loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::struct_expr (std::string struct_name,
-			 std::vector<std::unique_ptr<StructExprField>> &&fields)
+Builder::struct_expr (
+  std::string struct_name,
+  std::vector<std::unique_ptr<StructExprField>> &&fields) const
 {
   return std::unique_ptr<Expr> (
     new StructExprStructFields (path_in_expression ({struct_name}),
@@ -129,22 +150,23 @@  AstBuilder::struct_expr (std::string struct_name,
 }
 
 std::unique_ptr<StructExprField>
-AstBuilder::struct_expr_field (std::string field_name,
-			       std::unique_ptr<Expr> &&value)
+Builder::struct_expr_field (std::string field_name,
+			    std::unique_ptr<Expr> &&value) const
 {
   return std::unique_ptr<StructExprField> (
     new StructExprFieldIdentifierValue (field_name, std::move (value), loc));
 }
 
 std::unique_ptr<Expr>
-AstBuilder::field_access (std::unique_ptr<Expr> &&instance, std::string field)
+Builder::field_access (std::unique_ptr<Expr> &&instance,
+		       std::string field) const
 {
   return std::unique_ptr<Expr> (
     new FieldAccessExpr (std::move (instance), field, {}, loc));
 }
 
 std::unique_ptr<Pattern>
-AstBuilder::wildcard ()
+Builder::wildcard () const
 {
   return std::unique_ptr<Pattern> (new WildcardPattern (loc));
 }
diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h
index c0b4fa7b2cb..5c33954131f 100644
--- a/gcc/rust/ast/rust-ast-builder.h
+++ b/gcc/rust/ast/rust-ast-builder.h
@@ -28,80 +28,93 @@  namespace AST {
 /* Builder class with helper methods to create AST nodes. This builder is
  * tailored towards generating multiple AST nodes from a single location, and
  * may not be suitable to other purposes */
-class AstBuilder
+class Builder
 {
 public:
-  AstBuilder (location_t loc) : loc (loc) {}
+  Builder (location_t loc) : loc (loc) {}
+
+  /* Create a string literal expression ("content") */
+  std::unique_ptr<Expr> literal_string (std::string &&content) const;
 
   /* Create an identifier expression (`variable`) */
-  std::unique_ptr<Expr> identifier (std::string name);
+  std::unique_ptr<Expr> identifier (std::string name) const;
 
   /* Create a tuple index expression (`receiver.0`) */
-  std::unique_ptr<Expr> tuple_idx (std::string receiver, int idx);
+  std::unique_ptr<Expr> tuple_idx (std::string receiver, int idx) const;
 
   /* Create a reference to an expression (`&of`) */
-  std::unique_ptr<Expr> ref (std::unique_ptr<Expr> &&of, bool mut = false);
+  std::unique_ptr<Expr> ref (std::unique_ptr<Expr> &&of,
+			     bool mut = false) const;
 
   /* Create a dereference of an expression (`*of`) */
-  std::unique_ptr<Expr> deref (std::unique_ptr<Expr> &&of);
+  std::unique_ptr<Expr> deref (std::unique_ptr<Expr> &&of) const;
 
   /* Create a block with an optional tail expression */
   std::unique_ptr<Expr> block (std::vector<std::unique_ptr<Stmt>> &&stmts,
-			       std::unique_ptr<Expr> &&tail_expr = nullptr);
+			       std::unique_ptr<Expr> &&tail_expr
+			       = nullptr) const;
 
   /* Create a let binding with an optional type and initializer (`let <name> :
    * <type> = <init>`) */
   std::unique_ptr<Stmt> let (std::unique_ptr<Pattern> pattern,
 			     std::unique_ptr<Type> type = nullptr,
-			     std::unique_ptr<Expr> init = nullptr);
+			     std::unique_ptr<Expr> init = nullptr) const;
 
   /**
    * Create a call expression to a function, struct or enum variant, given its
    * arguments (`path(arg0, arg1, arg2)`)
    */
   std::unique_ptr<Expr> call (std::unique_ptr<Expr> &&path,
-			      std::vector<std::unique_ptr<Expr>> &&args);
+			      std::vector<std::unique_ptr<Expr>> &&args) const;
+
+  /**
+   * Create an array expression (`[member0, member1, member2]`)
+   */
+  std::unique_ptr<Expr>
+  array (std::vector<std::unique_ptr<Expr>> &&members) const;
 
   /* Empty function qualifiers, with no specific qualifiers */
-  FunctionQualifiers fn_qualifiers ();
+  FunctionQualifiers fn_qualifiers () const;
 
   /* Create a single path segment from one string */
-  PathExprSegment path_segment (std::string seg);
+  PathExprSegment path_segment (std::string seg) const;
 
   /* And similarly for type path segments */
-  std::unique_ptr<TypePathSegment> type_path_segment (std::string seg);
+  std::unique_ptr<TypePathSegment> type_path_segment (std::string seg) const;
 
   /* Create a Type from a single string - the most basic kind of type in our AST
    */
-  std::unique_ptr<Type> single_type_path (std::string type);
+  std::unique_ptr<Type> single_type_path (std::string type) const;
 
   /**
    * Create a path in expression from multiple segments (`Clone::clone`). You
    * do not need to separate the segments using `::`, you can simply provide a
    * vector of strings to the functions which will get turned into path segments
    */
-  PathInExpression path_in_expression (std::vector<std::string> &&segments);
+  PathInExpression
+  path_in_expression (std::vector<std::string> &&segments) const;
 
   /* Create a struct expression for unit structs (`S`) */
-  std::unique_ptr<Expr> struct_expr_struct (std::string struct_name);
+  std::unique_ptr<Expr> struct_expr_struct (std::string struct_name) const;
 
   /**
    * Create an expression for struct instantiation with fields (`S { a, b: c }`)
    */
   std::unique_ptr<Expr>
   struct_expr (std::string struct_name,
-	       std::vector<std::unique_ptr<StructExprField>> &&fields);
+	       std::vector<std::unique_ptr<StructExprField>> &&fields) const;
 
   /* Create a field expression for struct instantiation (`field_name: value`) */
   std::unique_ptr<StructExprField>
-  struct_expr_field (std::string field_name, std::unique_ptr<Expr> &&value);
+  struct_expr_field (std::string field_name,
+		     std::unique_ptr<Expr> &&value) const;
 
   /* Create a field access expression (`instance.field`) */
   std::unique_ptr<Expr> field_access (std::unique_ptr<Expr> &&instance,
-				      std::string field);
+				      std::string field) const;
 
   /* Create a wildcard pattern (`_`) */
-  std::unique_ptr<Pattern> wildcard ();
+  std::unique_ptr<Pattern> wildcard () const;
 
 private:
   /**
diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h
index 780d1a9d4e9..3e21d7e718d 100644
--- a/gcc/rust/ast/rust-builtin-ast-nodes.h
+++ b/gcc/rust/ast/rust-builtin-ast-nodes.h
@@ -132,6 +132,9 @@  public:
     return *this;
   }
 
+  FormatArgumentKind get_kind () const { return kind; }
+  const Expr &get_expr () const { return *expr; }
+
 private:
   FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
 		  std::unique_ptr<Expr> expr)
@@ -159,6 +162,7 @@  public:
   FormatArguments &operator= (const FormatArguments &other) = default;
 
   void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
+  const FormatArgument at (size_t idx) const { return args.at (idx); }
 
 private:
   std::vector<FormatArgument> args;
@@ -195,6 +199,7 @@  public:
   void accept_vis (AST::ASTVisitor &vis) override;
 
   const Fmt::Pieces &get_template () const { return template_pieces; }
+  const FormatArguments &get_arguments () const { return arguments; }
   virtual location_t get_locus () const override;
 
 private:
diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc
index e9927df1559..4177004eccf 100644
--- a/gcc/rust/expand/rust-derive.cc
+++ b/gcc/rust/expand/rust-derive.cc
@@ -24,7 +24,7 @@  namespace Rust {
 namespace AST {
 
 DeriveVisitor::DeriveVisitor (location_t loc)
-  : loc (loc), builder (AstBuilder (loc))
+  : loc (loc), builder (Builder (loc))
 {}
 
 std::unique_ptr<Item>
diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h
index cbe5bbbcbea..48f6594a636 100644
--- a/gcc/rust/expand/rust-derive.h
+++ b/gcc/rust/expand/rust-derive.h
@@ -41,7 +41,7 @@  protected:
   DeriveVisitor (location_t loc);
 
   location_t loc;
-  AstBuilder builder;
+  Builder builder;
 
 private:
   // the 4 "allowed" visitors, which a derive-visitor can specify and override
diff --git a/gcc/rust/expand/rust-expand-format-args.cc b/gcc/rust/expand/rust-expand-format-args.cc
index 276ffd58c50..3f76344ea5b 100644
--- a/gcc/rust/expand/rust-expand-format-args.cc
+++ b/gcc/rust/expand/rust-expand-format-args.cc
@@ -17,27 +17,122 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-expand-format-args.h"
+#include "rust-ast-fragment.h"
+#include "rust-ast.h"
 #include "rust-builtin-ast-nodes.h"
+#include "rust-ast-builder.h"
+#include "rust-diagnostics.h"
+#include "rust-expr.h"
+#include "rust-fmt.h"
+#include "rust-path.h"
+#include "rust-system.h"
+#include "rust-token.h"
 
 namespace Rust {
+namespace Fmt {
+
+static std::unique_ptr<AST::Expr>
+format_arg (const AST::Builder &builder, std::unique_ptr<AST::Expr> &&to_format,
+	    const std::string &trait)
+{
+  auto formatter_fn = std::unique_ptr<AST::Expr> (new AST::PathInExpression (
+    builder.path_in_expression ({"core", "fmt", trait, "fmt"})));
+
+  auto path = std::unique_ptr<AST::Expr> (new AST::PathInExpression (
+    builder.path_in_expression ({"core", "fmt", "ArgumentV1", "new"})));
+
+  auto args = std::vector<std::unique_ptr<AST::Expr>> ();
+  args.emplace_back (std::move (to_format));
+  args.emplace_back (std::move (formatter_fn));
+
+  return builder.call (std::move (path), std::move (args));
+}
+
+const std::string &
+get_trait_name (ffi::FormatSpec format_specifier)
+{
+  static const std::unordered_map<std::string, std::string> spec_map = {
+    {"", "Display"},   {"?", "Debug"},	  {"e", "LowerExp"},
+    {"E", "UpperExp"}, {"o", "Octal"},	  {"p", "Pointer"},
+    {"b", "Binary"},   {"x", "LowerHex"}, {"X", "UpperHex"},
+  };
+
+  auto it = spec_map.find (format_specifier.ty.to_string ());
+
+  if (it == spec_map.end ())
+    rust_unreachable ();
+
+  return it->second;
+}
 
 tl::optional<AST::Fragment>
-expand_format_args (AST::FormatArgs &fmt)
+expand_format_args (AST::FormatArgs &fmt,
+		    std::vector<std::unique_ptr<AST::Token>> &&tokens)
 {
+  auto loc = fmt.get_locus ();
+  auto builder = AST::Builder (loc);
+  auto &arguments = fmt.get_arguments ();
+
+  auto static_pieces = std::vector<std::unique_ptr<AST::Expr>> ();
+  auto args
+    = std::vector<std::pair<std::unique_ptr<AST::Expr>, ffi::FormatSpec>> ();
+
   for (const auto &node : fmt.get_template ().get_pieces ())
     {
       switch (node.tag)
 	{
-	case Fmt::ffi::Piece::Tag::String:
-	  // rust_debug ("[ARTHUR]: %s", node.string._0.c_str ());
+	case ffi::Piece::Tag::String:
+	  static_pieces.emplace_back (
+	    builder.literal_string (node.string._0.to_string ()));
+	  break;
+	  case ffi::Piece::Tag::NextArgument: {
+	    auto next_argument = node.next_argument._0;
+	    switch (node.next_argument._0.position.tag)
+	      {
+		case ffi::Position::Tag::ArgumentImplicitlyIs: {
+		  auto idx = next_argument.position.argument_implicitly_is._0;
+		  auto trait = next_argument.format;
+		  auto arg = arguments.at (idx);
+
+		  // FIXME(Arthur): This API sucks
+		  rust_assert (arg.get_kind ().kind
+			       == AST::FormatArgumentKind::Kind::Normal);
 
-	case Fmt::ffi::Piece::Tag::NextArgument:
-	  rust_debug ("[ARTHUR]: NextArgument");
+		  args.push_back ({arg.get_expr ().clone_expr (), trait});
+		}
+		break;
+	      case ffi::Position::Tag::ArgumentIs:
+	      case ffi::Position::Tag::ArgumentNamed:
+		rust_sorry_at (loc, "unhandled argument position specifier");
+		break;
+	      }
+	  }
 	  break;
 	}
     }
 
-  return tl::nullopt;
+  auto args_array = std::vector<std::unique_ptr<AST::Expr>> ();
+  for (auto &&arg : args)
+    args_array.emplace_back (format_arg (builder,
+					 builder.ref (std::move (arg.first)),
+					 get_trait_name (arg.second)));
+
+  auto pieces = builder.ref (builder.array (std::move (static_pieces)));
+  auto args_slice = builder.ref (builder.array (std::move (args_array)));
+
+  auto final_path = make_unique<AST::PathInExpression> (
+    builder.path_in_expression ({"core", "fmt", "Arguments", "new_v1"}));
+  auto final_args = std::vector<std::unique_ptr<AST::Expr>> ();
+  final_args.emplace_back (std::move (pieces));
+  final_args.emplace_back (std::move (args_slice));
+
+  auto final_call
+    = builder.call (std::move (final_path), std::move (final_args));
+
+  auto node = AST::SingleASTNode (std::move (final_call));
+
+  return AST::Fragment ({node}, std::move (tokens));
 }
 
+} // namespace Fmt
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-expand-format-args.h b/gcc/rust/expand/rust-expand-format-args.h
index 1481f3605ed..0a17de53597 100644
--- a/gcc/rust/expand/rust-expand-format-args.h
+++ b/gcc/rust/expand/rust-expand-format-args.h
@@ -23,10 +23,13 @@ 
 #include "rust-ast-fragment.h"
 
 namespace Rust {
+namespace Fmt {
 
 tl::optional<AST::Fragment>
-expand_format_args (AST::FormatArgs &fmt);
+expand_format_args (AST::FormatArgs &fmt,
+		    std::vector<std::unique_ptr<AST::Token>> &&tokens);
 
+} // namespace Fmt
 } // namespace Rust
 
 #endif //! RUST_EXPAND_FORMAT_ARGS_H
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index 8cf32051c7a..112713a4f97 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -20,6 +20,7 @@ 
 #include "libproc_macro_internal/tokenstream.h"
 #include "rust-ast-full-decls.h"
 #include "rust-builtin-ast-nodes.h"
+#include "rust-expand-format-args.h"
 #include "rust-token-converter.h"
 #include "rust-system.h"
 #include "rust-macro-builtins.h"
@@ -1102,13 +1103,23 @@  MacroBuiltin::format_args_handler (location_t invoc_locus,
   // TODO: we now need to take care of creating `unfinished_literal`? this is
   // for creating the `template`
 
-  auto fmt_args_node = new AST::FormatArgs (invoc_locus, std::move (pieces),
-					    std::move (input->args));
-  auto node = std::unique_ptr<AST::Expr> (fmt_args_node);
-  auto single_node = AST::SingleASTNode (std::move (node));
+  auto fmt_args_node = AST::FormatArgs (invoc_locus, std::move (pieces),
+					std::move (input->args));
 
-  return AST::Fragment ({std::move (single_node)},
-			invoc.get_delim_tok_tree ().to_token_stream ());
+  auto expanded
+    = Fmt::expand_format_args (fmt_args_node,
+			       invoc.get_delim_tok_tree ().to_token_stream ());
+
+  if (!expanded.has_value ())
+    return AST::Fragment::create_error ();
+
+  return *expanded;
+
+  // auto node = std::unique_ptr<AST::Expr> (fmt_args_node);
+  // auto single_node = AST::SingleASTNode (std::move (node));
+
+  // return AST::Fragment ({std::move (single_node)},
+  // 	invoc.get_delim_tok_tree ().to_token_stream ());
 }
 
 tl::optional<AST::Fragment>