@@ -17,53 +17,73 @@
// <http://www.gnu.org/licenses/>.
#include "rust-ast-builder.h"
+#include "rust-ast-full-decls.h"
#include "rust-ast-full.h"
+#include "rust-expr.h"
+#include "rust-token.h"
+#include "rust-make-unique.h"
namespace Rust {
namespace AST {
std::unique_ptr<Expr>
-AstBuilder::call (std::unique_ptr<Expr> &&path,
- std::vector<std::unique_ptr<Expr>> &&args)
+Builder::literal_string (std::string &&content) const
+{
+ return std::unique_ptr<Expr> (
+ new AST::LiteralExpr (std::move (content), Literal::LitType::STRING,
+ PrimitiveCoreType::CORETYPE_STR, {}, loc));
+}
+
+std::unique_ptr<Expr>
+Builder::call (std::unique_ptr<Expr> &&path,
+ std::vector<std::unique_ptr<Expr>> &&args) const
{
return std::unique_ptr<Expr> (
new CallExpr (std::move (path), std::move (args), {}, loc));
}
std::unique_ptr<Expr>
-AstBuilder::identifier (std::string name)
+Builder::array (std::vector<std::unique_ptr<Expr>> &&members) const
+{
+ auto elts = Rust::make_unique<ArrayElemsValues> (std::move (members), loc);
+
+ return std::unique_ptr<Expr> (new ArrayExpr (std::move (elts), {}, {}, loc));
+}
+
+std::unique_ptr<Expr>
+Builder::identifier (std::string name) const
{
return std::unique_ptr<Expr> (new IdentifierExpr (name, {}, loc));
}
std::unique_ptr<Expr>
-AstBuilder::tuple_idx (std::string receiver, int idx)
+Builder::tuple_idx (std::string receiver, int idx) const
{
return std::unique_ptr<Expr> (
new TupleIndexExpr (identifier (receiver), idx, {}, loc));
}
FunctionQualifiers
-AstBuilder::fn_qualifiers ()
+Builder::fn_qualifiers () const
{
return FunctionQualifiers (loc, Async::No, Const::No, Unsafety::Normal);
}
PathExprSegment
-AstBuilder::path_segment (std::string seg)
+Builder::path_segment (std::string seg) const
{
return PathExprSegment (PathIdentSegment (seg, loc), loc);
}
std::unique_ptr<TypePathSegment>
-AstBuilder::type_path_segment (std::string seg)
+Builder::type_path_segment (std::string seg) const
{
return std::unique_ptr<TypePathSegment> (
new TypePathSegment (seg, false, loc));
}
std::unique_ptr<Type>
-AstBuilder::single_type_path (std::string type)
+Builder::single_type_path (std::string type) const
{
auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
segments.emplace_back (type_path_segment (type));
@@ -72,7 +92,7 @@ AstBuilder::single_type_path (std::string type)
}
PathInExpression
-AstBuilder::path_in_expression (std::vector<std::string> &&segments)
+Builder::path_in_expression (std::vector<std::string> &&segments) const
{
auto path_segments = std::vector<PathExprSegment> ();
for (auto &seg : segments)
@@ -82,8 +102,8 @@ AstBuilder::path_in_expression (std::vector<std::string> &&segments)
}
std::unique_ptr<Expr>
-AstBuilder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
- std::unique_ptr<Expr> &&tail_expr)
+Builder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
+ std::unique_ptr<Expr> &&tail_expr) const
{
return std::unique_ptr<Expr> (new BlockExpr (std::move (stmts),
std::move (tail_expr), {}, {},
@@ -91,8 +111,8 @@ AstBuilder::block (std::vector<std::unique_ptr<Stmt>> &&stmts,
}
std::unique_ptr<Stmt>
-AstBuilder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
- std::unique_ptr<Expr> init)
+Builder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
+ std::unique_ptr<Expr> init) const
{
return std::unique_ptr<Stmt> (new LetStmt (std::move (pattern),
std::move (init), std::move (type),
@@ -100,28 +120,29 @@ AstBuilder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type,
}
std::unique_ptr<Expr>
-AstBuilder::ref (std::unique_ptr<Expr> &&of, bool mut)
+Builder::ref (std::unique_ptr<Expr> &&of, bool mut) const
{
return std::unique_ptr<Expr> (
new BorrowExpr (std::move (of), mut, /* is double */ false, {}, loc));
}
std::unique_ptr<Expr>
-AstBuilder::deref (std::unique_ptr<Expr> &&of)
+Builder::deref (std::unique_ptr<Expr> &&of) const
{
return std::unique_ptr<Expr> (new DereferenceExpr (std::move (of), {}, loc));
}
std::unique_ptr<Expr>
-AstBuilder::struct_expr_struct (std::string struct_name)
+Builder::struct_expr_struct (std::string struct_name) const
{
return std::unique_ptr<Expr> (
new StructExprStruct (path_in_expression ({struct_name}), {}, {}, loc));
}
std::unique_ptr<Expr>
-AstBuilder::struct_expr (std::string struct_name,
- std::vector<std::unique_ptr<StructExprField>> &&fields)
+Builder::struct_expr (
+ std::string struct_name,
+ std::vector<std::unique_ptr<StructExprField>> &&fields) const
{
return std::unique_ptr<Expr> (
new StructExprStructFields (path_in_expression ({struct_name}),
@@ -129,22 +150,23 @@ AstBuilder::struct_expr (std::string struct_name,
}
std::unique_ptr<StructExprField>
-AstBuilder::struct_expr_field (std::string field_name,
- std::unique_ptr<Expr> &&value)
+Builder::struct_expr_field (std::string field_name,
+ std::unique_ptr<Expr> &&value) const
{
return std::unique_ptr<StructExprField> (
new StructExprFieldIdentifierValue (field_name, std::move (value), loc));
}
std::unique_ptr<Expr>
-AstBuilder::field_access (std::unique_ptr<Expr> &&instance, std::string field)
+Builder::field_access (std::unique_ptr<Expr> &&instance,
+ std::string field) const
{
return std::unique_ptr<Expr> (
new FieldAccessExpr (std::move (instance), field, {}, loc));
}
std::unique_ptr<Pattern>
-AstBuilder::wildcard ()
+Builder::wildcard () const
{
return std::unique_ptr<Pattern> (new WildcardPattern (loc));
}
@@ -28,80 +28,93 @@ namespace AST {
/* Builder class with helper methods to create AST nodes. This builder is
* tailored towards generating multiple AST nodes from a single location, and
* may not be suitable to other purposes */
-class AstBuilder
+class Builder
{
public:
- AstBuilder (location_t loc) : loc (loc) {}
+ Builder (location_t loc) : loc (loc) {}
+
+ /* Create a string literal expression ("content") */
+ std::unique_ptr<Expr> literal_string (std::string &&content) const;
/* Create an identifier expression (`variable`) */
- std::unique_ptr<Expr> identifier (std::string name);
+ std::unique_ptr<Expr> identifier (std::string name) const;
/* Create a tuple index expression (`receiver.0`) */
- std::unique_ptr<Expr> tuple_idx (std::string receiver, int idx);
+ std::unique_ptr<Expr> tuple_idx (std::string receiver, int idx) const;
/* Create a reference to an expression (`&of`) */
- std::unique_ptr<Expr> ref (std::unique_ptr<Expr> &&of, bool mut = false);
+ std::unique_ptr<Expr> ref (std::unique_ptr<Expr> &&of,
+ bool mut = false) const;
/* Create a dereference of an expression (`*of`) */
- std::unique_ptr<Expr> deref (std::unique_ptr<Expr> &&of);
+ std::unique_ptr<Expr> deref (std::unique_ptr<Expr> &&of) const;
/* Create a block with an optional tail expression */
std::unique_ptr<Expr> block (std::vector<std::unique_ptr<Stmt>> &&stmts,
- std::unique_ptr<Expr> &&tail_expr = nullptr);
+ std::unique_ptr<Expr> &&tail_expr
+ = nullptr) const;
/* Create a let binding with an optional type and initializer (`let <name> :
* <type> = <init>`) */
std::unique_ptr<Stmt> let (std::unique_ptr<Pattern> pattern,
std::unique_ptr<Type> type = nullptr,
- std::unique_ptr<Expr> init = nullptr);
+ std::unique_ptr<Expr> init = nullptr) const;
/**
* Create a call expression to a function, struct or enum variant, given its
* arguments (`path(arg0, arg1, arg2)`)
*/
std::unique_ptr<Expr> call (std::unique_ptr<Expr> &&path,
- std::vector<std::unique_ptr<Expr>> &&args);
+ std::vector<std::unique_ptr<Expr>> &&args) const;
+
+ /**
+ * Create an array expression (`[member0, member1, member2]`)
+ */
+ std::unique_ptr<Expr>
+ array (std::vector<std::unique_ptr<Expr>> &&members) const;
/* Empty function qualifiers, with no specific qualifiers */
- FunctionQualifiers fn_qualifiers ();
+ FunctionQualifiers fn_qualifiers () const;
/* Create a single path segment from one string */
- PathExprSegment path_segment (std::string seg);
+ PathExprSegment path_segment (std::string seg) const;
/* And similarly for type path segments */
- std::unique_ptr<TypePathSegment> type_path_segment (std::string seg);
+ std::unique_ptr<TypePathSegment> type_path_segment (std::string seg) const;
/* Create a Type from a single string - the most basic kind of type in our AST
*/
- std::unique_ptr<Type> single_type_path (std::string type);
+ std::unique_ptr<Type> single_type_path (std::string type) const;
/**
* Create a path in expression from multiple segments (`Clone::clone`). You
* do not need to separate the segments using `::`, you can simply provide a
* vector of strings to the functions which will get turned into path segments
*/
- PathInExpression path_in_expression (std::vector<std::string> &&segments);
+ PathInExpression
+ path_in_expression (std::vector<std::string> &&segments) const;
/* Create a struct expression for unit structs (`S`) */
- std::unique_ptr<Expr> struct_expr_struct (std::string struct_name);
+ std::unique_ptr<Expr> struct_expr_struct (std::string struct_name) const;
/**
* Create an expression for struct instantiation with fields (`S { a, b: c }`)
*/
std::unique_ptr<Expr>
struct_expr (std::string struct_name,
- std::vector<std::unique_ptr<StructExprField>> &&fields);
+ std::vector<std::unique_ptr<StructExprField>> &&fields) const;
/* Create a field expression for struct instantiation (`field_name: value`) */
std::unique_ptr<StructExprField>
- struct_expr_field (std::string field_name, std::unique_ptr<Expr> &&value);
+ struct_expr_field (std::string field_name,
+ std::unique_ptr<Expr> &&value) const;
/* Create a field access expression (`instance.field`) */
std::unique_ptr<Expr> field_access (std::unique_ptr<Expr> &&instance,
- std::string field);
+ std::string field) const;
/* Create a wildcard pattern (`_`) */
- std::unique_ptr<Pattern> wildcard ();
+ std::unique_ptr<Pattern> wildcard () const;
private:
/**
@@ -132,6 +132,9 @@ public:
return *this;
}
+ FormatArgumentKind get_kind () const { return kind; }
+ const Expr &get_expr () const { return *expr; }
+
private:
FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
std::unique_ptr<Expr> expr)
@@ -159,6 +162,7 @@ public:
FormatArguments &operator= (const FormatArguments &other) = default;
void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
+ const FormatArgument at (size_t idx) const { return args.at (idx); }
private:
std::vector<FormatArgument> args;
@@ -195,6 +199,7 @@ public:
void accept_vis (AST::ASTVisitor &vis) override;
const Fmt::Pieces &get_template () const { return template_pieces; }
+ const FormatArguments &get_arguments () const { return arguments; }
virtual location_t get_locus () const override;
private:
@@ -24,7 +24,7 @@ namespace Rust {
namespace AST {
DeriveVisitor::DeriveVisitor (location_t loc)
- : loc (loc), builder (AstBuilder (loc))
+ : loc (loc), builder (Builder (loc))
{}
std::unique_ptr<Item>
@@ -41,7 +41,7 @@ protected:
DeriveVisitor (location_t loc);
location_t loc;
- AstBuilder builder;
+ Builder builder;
private:
// the 4 "allowed" visitors, which a derive-visitor can specify and override
@@ -17,27 +17,122 @@
// <http://www.gnu.org/licenses/>.
#include "rust-expand-format-args.h"
+#include "rust-ast-fragment.h"
+#include "rust-ast.h"
#include "rust-builtin-ast-nodes.h"
+#include "rust-ast-builder.h"
+#include "rust-diagnostics.h"
+#include "rust-expr.h"
+#include "rust-fmt.h"
+#include "rust-path.h"
+#include "rust-system.h"
+#include "rust-token.h"
namespace Rust {
+namespace Fmt {
+
+static std::unique_ptr<AST::Expr>
+format_arg (const AST::Builder &builder, std::unique_ptr<AST::Expr> &&to_format,
+ const std::string &trait)
+{
+ auto formatter_fn = std::unique_ptr<AST::Expr> (new AST::PathInExpression (
+ builder.path_in_expression ({"core", "fmt", trait, "fmt"})));
+
+ auto path = std::unique_ptr<AST::Expr> (new AST::PathInExpression (
+ builder.path_in_expression ({"core", "fmt", "ArgumentV1", "new"})));
+
+ auto args = std::vector<std::unique_ptr<AST::Expr>> ();
+ args.emplace_back (std::move (to_format));
+ args.emplace_back (std::move (formatter_fn));
+
+ return builder.call (std::move (path), std::move (args));
+}
+
+const std::string &
+get_trait_name (ffi::FormatSpec format_specifier)
+{
+ static const std::unordered_map<std::string, std::string> spec_map = {
+ {"", "Display"}, {"?", "Debug"}, {"e", "LowerExp"},
+ {"E", "UpperExp"}, {"o", "Octal"}, {"p", "Pointer"},
+ {"b", "Binary"}, {"x", "LowerHex"}, {"X", "UpperHex"},
+ };
+
+ auto it = spec_map.find (format_specifier.ty.to_string ());
+
+ if (it == spec_map.end ())
+ rust_unreachable ();
+
+ return it->second;
+}
tl::optional<AST::Fragment>
-expand_format_args (AST::FormatArgs &fmt)
+expand_format_args (AST::FormatArgs &fmt,
+ std::vector<std::unique_ptr<AST::Token>> &&tokens)
{
+ auto loc = fmt.get_locus ();
+ auto builder = AST::Builder (loc);
+ auto &arguments = fmt.get_arguments ();
+
+ auto static_pieces = std::vector<std::unique_ptr<AST::Expr>> ();
+ auto args
+ = std::vector<std::pair<std::unique_ptr<AST::Expr>, ffi::FormatSpec>> ();
+
for (const auto &node : fmt.get_template ().get_pieces ())
{
switch (node.tag)
{
- case Fmt::ffi::Piece::Tag::String:
- // rust_debug ("[ARTHUR]: %s", node.string._0.c_str ());
+ case ffi::Piece::Tag::String:
+ static_pieces.emplace_back (
+ builder.literal_string (node.string._0.to_string ()));
+ break;
+ case ffi::Piece::Tag::NextArgument: {
+ auto next_argument = node.next_argument._0;
+ switch (node.next_argument._0.position.tag)
+ {
+ case ffi::Position::Tag::ArgumentImplicitlyIs: {
+ auto idx = next_argument.position.argument_implicitly_is._0;
+ auto trait = next_argument.format;
+ auto arg = arguments.at (idx);
+
+ // FIXME(Arthur): This API sucks
+ rust_assert (arg.get_kind ().kind
+ == AST::FormatArgumentKind::Kind::Normal);
- case Fmt::ffi::Piece::Tag::NextArgument:
- rust_debug ("[ARTHUR]: NextArgument");
+ args.push_back ({arg.get_expr ().clone_expr (), trait});
+ }
+ break;
+ case ffi::Position::Tag::ArgumentIs:
+ case ffi::Position::Tag::ArgumentNamed:
+ rust_sorry_at (loc, "unhandled argument position specifier");
+ break;
+ }
+ }
break;
}
}
- return tl::nullopt;
+ auto args_array = std::vector<std::unique_ptr<AST::Expr>> ();
+ for (auto &&arg : args)
+ args_array.emplace_back (format_arg (builder,
+ builder.ref (std::move (arg.first)),
+ get_trait_name (arg.second)));
+
+ auto pieces = builder.ref (builder.array (std::move (static_pieces)));
+ auto args_slice = builder.ref (builder.array (std::move (args_array)));
+
+ auto final_path = make_unique<AST::PathInExpression> (
+ builder.path_in_expression ({"core", "fmt", "Arguments", "new_v1"}));
+ auto final_args = std::vector<std::unique_ptr<AST::Expr>> ();
+ final_args.emplace_back (std::move (pieces));
+ final_args.emplace_back (std::move (args_slice));
+
+ auto final_call
+ = builder.call (std::move (final_path), std::move (final_args));
+
+ auto node = AST::SingleASTNode (std::move (final_call));
+
+ return AST::Fragment ({node}, std::move (tokens));
}
+} // namespace Fmt
} // namespace Rust
@@ -23,10 +23,13 @@
#include "rust-ast-fragment.h"
namespace Rust {
+namespace Fmt {
tl::optional<AST::Fragment>
-expand_format_args (AST::FormatArgs &fmt);
+expand_format_args (AST::FormatArgs &fmt,
+ std::vector<std::unique_ptr<AST::Token>> &&tokens);
+} // namespace Fmt
} // namespace Rust
#endif //! RUST_EXPAND_FORMAT_ARGS_H
@@ -20,6 +20,7 @@
#include "libproc_macro_internal/tokenstream.h"
#include "rust-ast-full-decls.h"
#include "rust-builtin-ast-nodes.h"
+#include "rust-expand-format-args.h"
#include "rust-token-converter.h"
#include "rust-system.h"
#include "rust-macro-builtins.h"
@@ -1102,13 +1103,23 @@ MacroBuiltin::format_args_handler (location_t invoc_locus,
// 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));
+ auto fmt_args_node = AST::FormatArgs (invoc_locus, std::move (pieces),
+ std::move (input->args));
- return AST::Fragment ({std::move (single_node)},
- invoc.get_delim_tok_tree ().to_token_stream ());
+ auto expanded
+ = Fmt::expand_format_args (fmt_args_node,
+ invoc.get_delim_tok_tree ().to_token_stream ());
+
+ if (!expanded.has_value ())
+ return AST::Fragment::create_error ();
+
+ return *expanded;
+
+ // 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>