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 --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 -- 2.45.2