diff options
-rw-r--r-- | gcc/rust/ast/rust-ast.cc | 51 | ||||
-rw-r--r-- | gcc/rust/ast/rust-builtin-ast-nodes.h | 133 | ||||
-rw-r--r-- | gcc/rust/ast/rust-fmt.cc | 38 | ||||
-rw-r--r-- | gcc/rust/ast/rust-fmt.h | 21 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins.cc | 182 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-base.cc | 1 | ||||
-rw-r--r-- | libgrust/libformat_parser/src/bin.rs | 5 | ||||
-rw-r--r-- | libgrust/libformat_parser/src/lib.rs | 63 |
8 files changed, 416 insertions, 78 deletions
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 5d571b4..f3dabc6 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see #include "rust-ast.h" #include "optional.h" +#include "rust-builtin-ast-nodes.h" #include "rust-system.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" @@ -5054,6 +5055,56 @@ FormatArgs::accept_vis (ASTVisitor &vis) vis.visit (*this); } +std::string +FormatArgs::as_string () const +{ + // FIXME(Arthur): Improve + return "FormatArgs"; +} + +location_t +FormatArgs::get_locus () const +{ + rust_unreachable (); +} + +bool +FormatArgs::is_expr_without_block () const +{ + return false; +} + +void +FormatArgs::mark_for_strip () +{ + marked_for_strip = true; +} + +bool +FormatArgs::is_marked_for_strip () const +{ + return marked_for_strip; +} + +std::vector<Attribute> & +FormatArgs::get_outer_attrs () +{ + rust_unreachable (); +} + +void FormatArgs::set_outer_attrs (std::vector<Attribute>) +{ + rust_unreachable (); +} + +Expr * +FormatArgs::clone_expr_impl () const +{ + std::cerr << "[ARTHUR] cloning FormatArgs! " << std::endl; + + return new FormatArgs (*this); +} + } // namespace AST std::ostream & diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h index 3998fbf..6e26717 100644 --- a/gcc/rust/ast/rust-builtin-ast-nodes.h +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -59,9 +59,17 @@ namespace AST { // └─┘ └─┘ // positions (could be names, numbers, empty, or `*`) +// FIXME: Merge with the class below this one? class FormatArgumentKind { public: + enum class Kind + { + Normal, + Named, + Captured, + } kind; + Identifier &get_ident () { rust_assert (kind == Kind::Captured || kind == Kind::Named); @@ -69,25 +77,90 @@ public: return ident.value (); } -private: - enum class Kind + FormatArgumentKind (Kind kind, tl::optional<Identifier> ident) + : kind (kind), ident (ident) + {} + + FormatArgumentKind (const FormatArgumentKind &other) { - Normal, - Named, - Captured, - } kind; + kind = other.kind; + ident = other.ident; + } + + FormatArgumentKind operator= (const FormatArgumentKind &other) + { + kind = other.kind; + ident = other.ident; + return *this; + } + +private: tl::optional<Identifier> ident; }; class FormatArgument { +public: + static FormatArgument normal (std::unique_ptr<Expr> expr) + { + return FormatArgument (FormatArgumentKind::Kind::Normal, tl::nullopt, + std::move (expr)); + } + + static FormatArgument named (Identifier ident, std::unique_ptr<Expr> expr) + { + return FormatArgument (FormatArgumentKind::Kind::Named, ident, + std::move (expr)); + } + + static FormatArgument captured (Identifier ident, std::unique_ptr<Expr> expr) + { + return FormatArgument (FormatArgumentKind::Kind::Captured, ident, + std::move (expr)); + } + + FormatArgument (const FormatArgument &other) + : kind (other.kind), expr (other.expr->clone_expr ()) + {} + + FormatArgument operator= (const FormatArgument &other) + { + kind = other.kind; + expr = other.expr->clone_expr (); + + return *this; + } + +private: + FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident, + std::unique_ptr<Expr> expr) + : kind (FormatArgumentKind (kind, ident)), expr (std::move (expr)) + {} + FormatArgumentKind kind; std::unique_ptr<Expr> expr; }; class FormatArguments { +public: + FormatArguments () {} + FormatArguments (FormatArguments &&) = default; + FormatArguments (const FormatArguments &other) + { + args = std::vector<FormatArgument> (); + args.reserve (other.args.size ()); + + for (const auto &arg : other.args) + args.emplace_back (arg); + }; + + FormatArguments &operator= (const FormatArguments &other) = default; + + void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); } + +private: std::vector<FormatArgument> args; }; @@ -100,7 +173,7 @@ class FormatArguments // format_args!("result: {}", some_result))` -> `format_args!("heyo result: {}", // some_result)` // FIXME: Move to rust-macro.h -class FormatArgs : public Visitable +class FormatArgs : public Expr { public: enum class Newline @@ -109,18 +182,56 @@ public: No }; - FormatArgs (location_t loc, Fmt::PieceSlice template_str, - FormatArguments arguments) + FormatArgs (location_t loc, Fmt::Pieces &&template_str, + FormatArguments &&arguments) : loc (loc), template_str (std::move (template_str)), arguments (std::move (arguments)) {} - void accept_vis (AST::ASTVisitor &vis); + FormatArgs (FormatArgs &&other) + : loc (std::move (other.loc)), + template_str (std::move (other.template_str)), + arguments (std::move (other.arguments)) + { + std::cerr << "[ARTHUR] moving FormatArgs" << std::endl; + } + + // FIXME: This might be invalid - we are reusing the same memory allocated + // on the Rust side for `other`. This is probably valid as long as we only + // ever read that memory and never write to it. + FormatArgs (const FormatArgs &other) + : loc (other.loc), template_str (other.template_str), + arguments (other.arguments) + { + std::cerr << "[ARTHUR] copying FormatArgs" << std::endl; + } + + // FormatArgs &operator= (const FormatArgs &other) = default; + // : template_str (other.template_str), arguments (other.arguments) + // {} + + void accept_vis (AST::ASTVisitor &vis) override; private: location_t loc; - Fmt::PieceSlice template_str; + // FIXME: This probably needs to be a separate type - it is one in rustc's + // expansion of format_args!(). There is extra handling associated with it. + // we can maybe do that in rust-fmt.cc? in collect_pieces()? like do the + // transformation into something we can handle better + Fmt::Pieces template_str; FormatArguments arguments; + + bool marked_for_strip = false; + +protected: + virtual std::string as_string () const override; + virtual location_t get_locus () const override; + virtual bool is_expr_without_block () const override; + virtual void mark_for_strip () override; + virtual bool is_marked_for_strip () const override; + virtual std::vector<Attribute> &get_outer_attrs () override; + virtual void set_outer_attrs (std::vector<Attribute>) override; + virtual Expr *clone_expr_impl () const override; }; } // namespace AST diff --git a/gcc/rust/ast/rust-fmt.cc b/gcc/rust/ast/rust-fmt.cc index 511e947..c367e30 100644 --- a/gcc/rust/ast/rust-fmt.cc +++ b/gcc/rust/ast/rust-fmt.cc @@ -23,9 +23,9 @@ namespace Rust { namespace Fmt { Pieces -Pieces::collect (std::string &&to_parse) +Pieces::collect (std::string &&to_parse, bool append_newline) { - auto piece_slice = collect_pieces (to_parse.c_str ()); + auto piece_slice = collect_pieces (to_parse.c_str (), append_newline); rust_debug ("[ARTHUR] %p, %lu", (const void *) piece_slice.base_ptr, piece_slice.len); @@ -37,7 +37,39 @@ Pieces::collect (std::string &&to_parse) return Pieces (piece_slice, std::move (to_parse)); } -Pieces::~Pieces () { destroy_pieces (slice); } +Pieces::~Pieces () +{ + std::cerr << "Arthur: destoying pieces. this: " << (void *) this + << " slice: " << slice.base_ptr << std::endl; + destroy_pieces (slice); +} + +Pieces::Pieces (const Pieces &other) : to_parse (other.to_parse) +{ + slice = clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap); + std::cerr << "Arthur: copying pieces: other.to_parse: " + << (void *) other.to_parse.c_str () + << " ours to_parse: " << (void *) to_parse.c_str () << std::endl; + // auto pieces = std::vector (slice.base_ptr, slice.base_ptr + slice.len); +} + +Pieces & +Pieces::operator= (const Pieces &other) +{ + slice = clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap); + to_parse = other.to_parse; + + return *this; +} + +Pieces::Pieces (Pieces &&other) + : slice ( + clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap)), + to_parse (std::move (other.to_parse)) +{ + std::cerr << "Arthur: moving pieces. to_parse: " << (void *) to_parse.c_str () + << " base_ptr/slice: " << (void *) slice.base_ptr << std::endl; +} } // namespace Fmt } // namespace Rust diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index 0bf9695..22447c4 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -222,7 +222,7 @@ struct Piece struct NextArgument_Body { - const Argument *_0; + Argument _0; }; Tag tag; @@ -243,7 +243,10 @@ struct PieceSlice extern "C" { PieceSlice -collect_pieces (const char *input); +collect_pieces (const char *input, bool append_newline); + +PieceSlice +clone_pieces (const Piece *base_ptr, size_t len, size_t cap); void destroy_pieces (PieceSlice); @@ -251,9 +254,21 @@ void destroy_pieces (PieceSlice); struct Pieces { - static Pieces collect (std::string &&to_parse); + static Pieces collect (std::string &&to_parse, bool append_newline); ~Pieces (); + Pieces (const Pieces &other); + Pieces &operator= (const Pieces &other); + + Pieces (Pieces &&other); + + // { + // slice = clone_pieces (&other.slice); + // to_parse = other.to_parse; + + // return *this; + // } + private: Pieces (PieceSlice slice, std::string &&to_parse) : slice (slice), to_parse (std::move (to_parse)) diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 9e6716c..b42d1ec 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -16,6 +16,7 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "expected.h" #include "libproc_macro_internal/tokenstream.h" #include "rust-ast-full-decls.h" #include "rust-builtin-ast-nodes.h" @@ -35,6 +36,7 @@ #include "rust-session-manager.h" #include "rust-attribute-values.h" #include "rust-fmt.h" +#include "rust-token.h" namespace Rust { @@ -956,34 +958,116 @@ MacroBuiltin::stringify_handler (location_t invoc_locus, return AST::Fragment ({node}, std::move (token)); } -tl::optional<AST::Fragment> -MacroBuiltin::format_args_handler (location_t invoc_locus, - AST::MacroInvocData &invoc, - AST::FormatArgs::Newline nl) +struct FormatArgsInput { - // Remove the delimiters from the macro invocation: - // the invoc data for `format_args!(fmt, arg1, arg2)` is `(fmt, arg1, arg2)`, - // so we pop the front and back to remove the parentheses (or curly brackets, - // or brackets) - auto tokens = invoc.get_delim_tok_tree ().to_token_stream (); - tokens.erase (tokens.begin ()); - tokens.pop_back (); + std::unique_ptr<AST::Expr> format_str; + AST::FormatArguments args; + // bool is_literal? +}; - auto append_newline = nl == AST::FormatArgs::Newline::Yes ? true : false; - auto fmt_arg - = parse_single_string_literal (append_newline ? BuiltinMacro::FormatArgsNl - : BuiltinMacro::FormatArgs, - invoc.get_delim_tok_tree (), invoc_locus, - invoc.get_expander ()); +struct FormatArgsParseError +{ + enum class Kind + { + MissingArguments + } kind; +}; + +static tl::expected<FormatArgsInput, FormatArgsParseError> +format_args_parse_arguments (AST::MacroInvocData &invoc) +{ + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + + // TODO: check if EOF - return that format_args!() requires at least one + // argument - if (!fmt_arg->is_literal ()) + auto args = AST::FormatArguments (); + auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser); + std::unique_ptr<AST::Expr> format_str = nullptr; + + // TODO: Handle the case where we're not parsing a string literal (macro + // invocation for e.g.) + if (parser.peek_current_token ()->get_id () == STRING_LITERAL) + format_str = parser.parse_literal_expr (); + + // TODO: Allow implicit captures ONLY if the the first arg is a string literal + // and not a macro invocation + + // TODO: How to consume all of the arguments until the delimiter? + + // TODO: What we then want to do is as follows: + // for each token, check if it is an identifier + // yes? is the next token an equal sign (=) + // yes? + // -> if that identifier is already present in our map, error + // out + // -> parse an expression, return a FormatArgument::Named + // no? + // -> if there have been named arguments before, error out + // (positional after named error) + // -> parse an expression, return a FormatArgument::Normal + while (parser.peek_current_token ()->get_id () != last_token_id) { - rust_sorry_at ( - invoc_locus, - "cannot yet use eager macro invocations as format strings"); - return AST::Fragment::create_empty (); + parser.skip_token (COMMA); + + if (parser.peek_current_token ()->get_id () == IDENTIFIER + && parser.peek (1)->get_id () == EQUAL) + { + // FIXME: This is ugly - just add a parser.parse_identifier()? + auto ident_tok = parser.peek_current_token (); + auto ident = Identifier (ident_tok); + + parser.skip_token (IDENTIFIER); + parser.skip_token (EQUAL); + + auto expr = parser.parse_expr (); + + // TODO: Handle graciously + if (!expr) + rust_unreachable (); + + args.push (AST::FormatArgument::named (ident, std::move (expr))); + } + else + { + auto expr = parser.parse_expr (); + + // TODO: Handle graciously + if (!expr) + rust_unreachable (); + + args.push (AST::FormatArgument::normal (std::move (expr))); + } + // we need to skip commas, don't we? } + return FormatArgsInput{std::move (format_str), std::move (args)}; +} + +tl::optional<AST::Fragment> +MacroBuiltin::format_args_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::FormatArgs::Newline nl) +{ + auto input = format_args_parse_arguments (invoc); + + // auto fmt_arg + // // FIXME: this eneds to be split up into a smaller function + // = parse_single_string_literal (append_newline ? + // BuiltinMacro::FormatArgsNl + // : BuiltinMacro::FormatArgs, + // invoc.get_delim_tok_tree (), invoc_locus, + // invoc.get_expander ()); + + // if (!fmt_arg->is_literal ()) + // { + // rust_sorry_at ( + // invoc_locus, + // "cannot yet use eager macro invocations as format strings"); + // return AST::Fragment::create_empty (); + // } + // FIXME: We need to handle this // // if it is not a literal, it's an eager macro invocation - return it // if (!fmt_expr->is_literal ()) @@ -993,38 +1077,54 @@ MacroBuiltin::format_args_handler (location_t invoc_locus, // token_tree.to_token_stream ()); // } - auto fmt_str = static_cast<AST::LiteralExpr &> (*fmt_arg.get ()); + // auto fmt_str = static_cast<AST::LiteralExpr &> (*fmt_arg.get ()); // Switch on the format string to know if the string is raw or cooked - switch (fmt_str.get_lit_type ()) - { - // case AST::Literal::RAW_STRING: - case AST::Literal::STRING: - break; - case AST::Literal::CHAR: - case AST::Literal::BYTE: - case AST::Literal::BYTE_STRING: - case AST::Literal::INT: - case AST::Literal::FLOAT: - case AST::Literal::BOOL: - case AST::Literal::ERROR: - rust_unreachable (); - } + // switch (fmt_str.get_lit_type ()) + // { + // // case AST::Literal::RAW_STRING: + // case AST::Literal::STRING: + // break; + // case AST::Literal::CHAR: + // case AST::Literal::BYTE: + // case AST::Literal::BYTE_STRING: + // case AST::Literal::INT: + // case AST::Literal::FLOAT: + // case AST::Literal::BOOL: + // case AST::Literal::ERROR: + // rust_unreachable (); + // } + + // Remove the delimiters from the macro invocation: + // the invoc data for `format_args!(fmt, arg1, arg2)` is `(fmt, arg1, arg2)`, + // so we pop the front and back to remove the parentheses (or curly brackets, + // or brackets) + auto tokens = invoc.get_delim_tok_tree ().to_token_stream (); + tokens.erase (tokens.begin ()); + tokens.pop_back (); std::stringstream stream; for (const auto &tok : tokens) stream << tok->as_string () << ' '; - rust_debug ("[ARTHUR]: `%s`", stream.str ().c_str ()); - - auto pieces = Fmt::Pieces::collect (stream.str ()); + auto append_newline = nl == AST::FormatArgs::Newline::Yes ? true : false; + auto pieces = Fmt::Pieces::collect (stream.str (), append_newline); // TODO: // do the transformation into an AST::FormatArgs node // return that // expand it during lowering - return AST::Fragment::create_empty (); + // 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)); + + return AST::Fragment ({std::move (single_node)}, + invoc.get_delim_tok_tree ().to_token_stream ()); } tl::optional<AST::Fragment> diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index fa37d62..54c0520 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -22,6 +22,7 @@ #include "rust-ast-lower-extern.h" #include "rust-ast.h" #include "rust-attribute-values.h" +#include "rust-diagnostics.h" #include "rust-item.h" #include "rust-system.h" diff --git a/libgrust/libformat_parser/src/bin.rs b/libgrust/libformat_parser/src/bin.rs index 4b1f903..5f46497 100644 --- a/libgrust/libformat_parser/src/bin.rs +++ b/libgrust/libformat_parser/src/bin.rs @@ -2,6 +2,9 @@ use libformat_parser::rust; fn main() { dbg!(rust::collect_pieces( - std::env::args().nth(1).unwrap().as_str() + std::env::args().nth(1).unwrap().as_str(), + None, + None, + false )); } diff --git a/libgrust/libformat_parser/src/lib.rs b/libgrust/libformat_parser/src/lib.rs index c164578..6bf78c4 100644 --- a/libgrust/libformat_parser/src/lib.rs +++ b/libgrust/libformat_parser/src/lib.rs @@ -77,20 +77,15 @@ mod ffi { /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. - #[derive(Clone, Debug, PartialEq)] + #[derive(Debug, Clone, PartialEq)] #[repr(C)] pub enum Piece<'a> { /// A literal string which should directly be emitted String(&'a str), /// This describes that formatting should process the next argument (as /// specified inside) for emission. - NextArgument(*const Argument<'a>), - } - - impl<'a> Drop for Piece<'a> { - fn drop(&mut self) { - println!("dropping Piece: {:?}", self) - } + // do we need a pointer here? we're doing big cloning anyway + NextArgument(Argument<'a>), } /// Representation of an argument specification. @@ -216,7 +211,7 @@ mod ffi { let ptr = Box::leak(x); let dst = Into::<Argument>::into(*ptr); - Piece::NextArgument(&dst as *const Argument) + Piece::NextArgument(dst) } } } @@ -321,8 +316,13 @@ mod ffi { pub mod rust { use generic_format_parser::{ParseMode, Parser, Piece}; - pub fn collect_pieces(input: &str) -> Vec<Piece<'_>> { - let parser = Parser::new(input, None, None, true, ParseMode::Format); + pub fn collect_pieces( + input: &str, + style: Option<usize>, + snippet: Option<String>, + append_newline: bool, + ) -> Vec<Piece<'_>> { + let parser = Parser::new(input, style, snippet, append_newline, ParseMode::Format); parser.into_iter().collect() } @@ -337,16 +337,18 @@ pub struct PieceSlice { } #[no_mangle] -pub extern "C" fn collect_pieces(input: *const libc::c_char) -> PieceSlice { +pub extern "C" fn collect_pieces(input: *const libc::c_char, append_newline: bool) -> PieceSlice { + dbg!(input); + // FIXME: Add comment let str = unsafe { CStr::from_ptr(input) }; - dbg!(str); // FIXME: No unwrap - let pieces: Vec<ffi::Piece<'_>> = rust::collect_pieces(str.to_str().unwrap()) - .into_iter() - .map(Into::into) - .collect(); + let pieces: Vec<ffi::Piece<'_>> = + rust::collect_pieces(str.to_str().unwrap(), None, None, append_newline) + .into_iter() + .map(Into::into) + .collect(); println!("[ARTHUR]: debug: {:?}, {:?}", pieces.as_ptr(), pieces.len()); @@ -358,6 +360,29 @@ pub extern "C" fn collect_pieces(input: *const libc::c_char) -> PieceSlice { } #[no_mangle] -pub extern "C" fn destroy_pieces(PieceSlice { base_ptr, len, cap }: PieceSlice) { - let _ = unsafe { Vec::from_raw_parts(base_ptr, len, cap) }; +pub unsafe extern "C" fn destroy_pieces(PieceSlice { base_ptr, len, cap }: PieceSlice) { + eprintln!("[ARTHUR] destroying pieces: {base_ptr:?} {len} {cap}"); + drop(Vec::from_raw_parts(base_ptr, len, cap)); +} + +#[no_mangle] +pub extern "C" fn clone_pieces( + base_ptr: *mut ffi::Piece<'static>, + len: usize, + cap: usize, +) -> PieceSlice { + eprintln!("[ARTHUR] cloning pieces: {base_ptr:?} {len} {cap}"); + + let v = unsafe { Vec::from_raw_parts(base_ptr, len, cap) }; + + let cloned_v = v.clone(); + + // FIXME: Add documentation + v.leak(); + + PieceSlice { + len: cloned_v.len(), + cap: cloned_v.capacity(), + base_ptr: dbg!(cloned_v.leak().as_mut_ptr()), + } } |