Skip to content

Commit

Permalink
fmt: Start working on format_args!() parser
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
CohenArthur committed Nov 9, 2023
1 parent 2c862b9 commit 43d188f
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 0 deletions.
1 change: 1 addition & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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 \
Expand Down
96 changes: 96 additions & 0 deletions gcc/rust/ast/rust-fmt.cc
Original file line number Diff line number Diff line change
@@ -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 ();
}

Fmt::ParseResult<tl::optional<Fmt::Format>>
Fmt::maybe_format (Fmt::Input input)
{
tl::optional<Fmt::Format> none = tl::nullopt;

return Fmt::Result (input, none);
}

Fmt::ParseResult<Fmt::Format>
Fmt::format (Input input)
{
return Fmt::Result (input, Format ());
}

Fmt::ParseResult<Fmt::Argument>
Fmt::argument (Input input)
{
return Fmt::Result (input, Argument ());
}

Fmt::ParseResult<Fmt::FormatSpec>
Fmt::format_spec (Input input)
{
return Fmt::Result (input, FormatSpec ());
}

Fmt::ParseResult<Fmt::Fill>
Fmt::fill (Input input)
{
return Fmt::Result (input, Fill ());
}

Fmt::ParseResult<Fmt::Align>
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);
}
}

Fmt::ParseResult<Fmt::Sign>
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
120 changes: 120 additions & 0 deletions gcc/rust/ast/rust-fmt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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> using ParseResult = tl::expected<Result<T>, Error>;

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 ParseResult<std::string> text (Input input);
static ParseResult<tl::optional<Format>> maybe_format (Input input);
static ParseResult<Format> format (Input input);
static ParseResult<Argument> argument (Input input);
static ParseResult<FormatSpec> format_spec (Input input);
static ParseResult<Fill> fill (Input input);
static ParseResult<Align> align (Input input);
static ParseResult<Sign> sign (Input input);
};

} // namespace Rust

#endif // ! RUST_FMT_H

0 comments on commit 43d188f

Please sign in to comment.