diff mbox series

[004/125] gccrs: fmt: Start working on format_args!() parser

Message ID 20240801145809.366388-6-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
This commit adds a base class for parsing the various constructs of a
Rust format string, according to the grammar in the reference:

https://doc.rust-lang.org/std/fmt/index.html#syntax

gcc/rust/ChangeLog:

	* Make-lang.in: Compile rust-fmt object
	* ast/rust-fmt.cc: New file.
	* ast/rust-fmt.h: New file.
---
 gcc/rust/Make-lang.in    |   1 +
 gcc/rust/ast/rust-fmt.cc |  96 ++++++++++++++++++++++++++++
 gcc/rust/ast/rust-fmt.h  | 133 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 gcc/rust/ast/rust-fmt.cc
 create mode 100644 gcc/rust/ast/rust-fmt.h
diff mbox series

Patch

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index e437c32e347..c0df49a7fee 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -100,6 +100,7 @@  GRS_OBJS = \
     rust/rust-proc-macro-invoc-lexer.o \
     rust/rust-macro-substitute-ctx.o \
     rust/rust-macro-builtins.o \
+	rust/rust-fmt.o \
     rust/rust-hir.o \
     rust/rust-hir-map.o \
     rust/rust-attributes.o \
diff --git a/gcc/rust/ast/rust-fmt.cc b/gcc/rust/ast/rust-fmt.cc
new file mode 100644
index 00000000000..9f9ba48f0c3
--- /dev/null
+++ b/gcc/rust/ast/rust-fmt.cc
@@ -0,0 +1,96 @@ 
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-fmt.h"
+
+namespace Rust {
+tl::expected<Fmt, Fmt::Error>
+Fmt::parse_fmt_string (Fmt::Input input)
+{
+  return Fmt ();
+}
+
+tl::expected<Fmt::Result<tl::optional<Fmt::Format>>, Fmt::Error>
+Fmt::maybe_format (Fmt::Input input)
+{
+  tl::optional<Fmt::Format> none = tl::nullopt;
+
+  return Fmt::Result (input, none);
+}
+
+tl::expected<Fmt::Result<Fmt::Format>, Fmt::Error>
+Fmt::format (Input input)
+{
+  return Fmt::Result (input, Format ());
+}
+
+tl::expected<Fmt::Result<Fmt::Argument>, Fmt::Error>
+Fmt::argument (Input input)
+{
+  return Fmt::Result (input, Argument ());
+}
+
+tl::expected<Fmt::Result<Fmt::FormatSpec>, Fmt::Error>
+Fmt::format_spec (Input input)
+{
+  return Fmt::Result (input, FormatSpec ());
+}
+
+tl::expected<Fmt::Result<Fmt::Fill>, Fmt::Error>
+Fmt::fill (Input input)
+{
+  return Fmt::Result (input, Fill ());
+}
+
+tl::expected<Fmt::Result<Fmt::Align>, Fmt::Error>
+Fmt::align (Input input)
+{
+  switch (input[0])
+    {
+    case '<':
+      return Fmt::Result (input.substr (1), Align::Left);
+    case '^':
+      return Fmt::Result (input.substr (1), Align::Top);
+    case '>':
+      return Fmt::Result (input.substr (1), Align::Right);
+    default:
+      // TODO: Store the character here
+      // TODO: Can we have proper error locations?
+      // TODO: Maybe we should use a Rust::Literal string instead of a string
+      return tl::make_unexpected (Error::Align);
+    }
+}
+
+tl::expected<Fmt::Result<Fmt::Sign>, Fmt::Error>
+Fmt::sign (Input input)
+{
+  switch (input[0])
+    {
+    case '+':
+      return Fmt::Result (input.substr (1), Sign::Plus);
+    case '-':
+      return Fmt::Result (input.substr (1), Sign::Minus);
+    default:
+      // TODO: Store the character here
+      // TODO: Can we have proper error locations?
+      // TODO: Maybe we should use a Rust::Literal string instead of a string
+      return tl::make_unexpected (Error::Sign);
+    }
+}
+
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h
new file mode 100644
index 00000000000..f3dd53da979
--- /dev/null
+++ b/gcc/rust/ast/rust-fmt.h
@@ -0,0 +1,133 @@ 
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_FMT_H
+#define RUST_FMT_H
+
+#include "expected.h"
+#include "optional.h"
+#include "rust-ast.h"
+#include "rust-system.h"
+
+namespace Rust {
+
+/**
+ * This class implements the parsing of Rust format strings according to the
+ * grammar here: https://doc.rust-lang.org/std/fmt/index.html#syntax
+ */
+// TODO: Are there features that are only present in specific Rust editions?
+class Fmt
+{
+public:
+  // TODO: Keep location information
+  // TODO: Switch to a Rust::AST::Literal here
+  using Input = std::string;
+
+  enum class Error
+  {
+    Align,
+    Sign,
+  };
+
+  template <typename T> class Result
+  {
+  public:
+    explicit Result (Input remaining_input, T result)
+      : remaining_input (remaining_input), result (result)
+    {}
+
+  private:
+    Input remaining_input;
+    T result;
+  };
+
+  // FIXME: Do not use an owned string here
+  static tl::expected<Fmt, Fmt::Error> parse_fmt_string (Input input);
+
+private:
+  // the parse functions should return the remaining input as well as the
+  // expected node let's look at nom
+  // TODO: no string view :( use an owned string for now?
+
+  template <typename T> struct ParseResult
+  {
+    tl::expected<Result<T>, Error> inner;
+
+    ParseResult (tl::expected<Result<T>, Error> inner) : inner (inner) {}
+    ParseResult operator= (tl::expected<Result<T>, Error> inner)
+    {
+      return ParseResult (inner);
+    }
+
+    Input remaining_input () { return inner->remaining_input; }
+    T value () { return inner->value; }
+  };
+
+  struct Format
+  {
+  };
+
+  struct Argument
+  {
+    enum struct Kind
+    {
+      Integer,
+      Identifier,
+    } kind;
+
+    int integer;
+    Identifier identifier;
+  };
+
+  struct FormatSpec
+  {
+  };
+
+  struct Fill
+  {
+    char to_fill;
+  };
+
+  enum class Align
+  {
+    Left,
+    Top,
+    Right
+  };
+
+  enum class Sign
+  {
+    Plus,
+    Minus
+  };
+
+  // let's do one function per rule in the BNF
+  static tl::expected<Result<std::string>, Error> text (Input input);
+  static tl::expected<Result<tl::optional<Format>>, Error>
+  maybe_format (Input input);
+  static tl::expected<Result<Format>, Error> format (Input input);
+  static tl::expected<Result<Argument>, Error> argument (Input input);
+  static tl::expected<Result<FormatSpec>, Error> format_spec (Input input);
+  static tl::expected<Result<Fill>, Error> fill (Input input);
+  static tl::expected<Result<Align>, Error> align (Input input);
+  static tl::expected<Result<Sign>, Error> sign (Input input);
+};
+
+} // namespace Rust
+
+#endif // ! RUST_FMT_H