gccrs: fmt: Start working on format_args!() parser

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.
This commit is contained in:
Arthur Cohen
2023-11-09 18:32:52 +01:00
parent a58f7df147
commit 473feb033d
3 changed files with 230 additions and 0 deletions

View File

@@ -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 \

96
gcc/rust/ast/rust-fmt.cc Normal file
View File

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

133
gcc/rust/ast/rust-fmt.h Normal file
View File

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