summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-06-08 12:37:51 +0800
committerJohn Hodge <tpg@mutabah.net>2016-06-08 12:37:51 +0800
commit40071822728499b9028400ddac3cd32fb884b2a0 (patch)
treebeabbf632622601b307beb8308f1098e9da91a15
parentd91e9415d3a3cd4c9cc5bfcee548d6b3b98867f5 (diff)
downloadmrust-40071822728499b9028400ddac3cd32fb884b2a0.tar.gz
Expand format_args! - Parse and (partially) emit
-rw-r--r--src/expand/format_args.cpp300
-rw-r--r--src/include/synext.hpp90
-rw-r--r--src/include/synext_decorator.hpp75
-rw-r--r--src/include/synext_macro.hpp40
4 files changed, 411 insertions, 94 deletions
diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp
index 1b8dfb54..6f9ea9ec 100644
--- a/src/expand/format_args.cpp
+++ b/src/expand/format_args.cpp
@@ -1,11 +1,254 @@
/*
*/
-#include <synext.hpp>
+#include <synext_macro.hpp>
#include "../parse/common.hpp"
#include "../parse/parseerror.hpp"
#include "../parse/tokentree.hpp"
#include "../parse/lex.hpp"
+namespace {
+
+ struct FmtArgs
+ {
+ enum class Align {
+ Unspec,
+ Left,
+ Center,
+ Right,
+ };
+ enum class Sign {
+ Unspec,
+ Plus,
+ Minus,
+ };
+
+ Align align = Align::Unspec;
+ char align_char = ' ';
+
+ Sign sign = Sign::Unspec;
+ bool alternate = false;
+ bool zero_pad = false;
+
+ bool width_is_arg = false;
+ unsigned int width = 0;
+
+ bool prec_is_arg = false;
+ unsigned int prec = 0;
+ };
+
+ struct FmtFrag
+ {
+ ::std::string leading_text;
+
+ unsigned int arg_index;
+
+ const char* trait_name;
+ // TODO: Support case where this hasn't been edited
+ FmtArgs args;
+ };
+
+ ::std::tuple< ::std::vector<FmtFrag>, ::std::string> parse_format_string(const Span& sp, const ::std::string& format_string, const ::std::map< ::std::string,unsigned int>& named, unsigned int n_free)
+ {
+ unsigned int n_named = named.size();
+ unsigned int next_free = 0;
+
+ ::std::vector<FmtFrag> frags;
+ ::std::string cur_literal;
+
+ const char* s = format_string.c_str();
+ for( ; *s; s ++)
+ {
+ if( *s != '{' )
+ {
+ if( *s == '}' ) {
+ s ++;
+ if( *s != '}' )
+ ERROR(sp, E0000, "'}' must be escaped as '}}' in format strings");
+ // - fall with *s == '}'
+ }
+ cur_literal += *s;
+ }
+ else
+ {
+ s ++;
+ if( *s == '{' ) {
+ cur_literal += '{';
+ continue ;
+ }
+
+ unsigned int index = ~0u;
+ const char* trait_name;
+ FmtArgs args;
+
+ // Formatting parameter
+ if( *s != ':' && *s != '}' ) {
+ // Parse either an integer or an identifer
+ TODO(sp, "Parse named/positional formatting fragment at \"" << s);
+ }
+ else {
+ // Leave (for now)
+ // - If index is ~0u at the end of this block, it's set to the next arg
+ // - This allows {:.*} to format correctly (taking <prec> then <arg>)
+ }
+
+ // If next character is ':', parse extra information
+ if( *s == ':' ) {
+ s ++; // eat ':'
+
+ // Alignment
+ if( s[0] != '\0' && (s[1] == '<' || s[1] == '^' || s[1] == '>') ) {
+ args.align_char = s[0];
+ s ++;
+ }
+ if( *s == '<' ) {
+ args.align = FmtArgs::Align::Left;
+ s ++;
+ }
+ else if( *s == '^' ) {
+ args.align = FmtArgs::Align::Center;
+ s ++;
+ }
+ else if( *s == '>' ) {
+ args.align = FmtArgs::Align::Right;
+ s ++;
+ }
+ else {
+ //args.align = FmtArgs::Align::Unspec;
+ }
+
+ // Sign
+ if( *s == '+' ) {
+ args.sign = FmtArgs::Sign::Plus;
+ s ++;
+ }
+ else if( *s == '-' ) {
+ args.sign = FmtArgs::Sign::Minus;
+ s ++;
+ }
+ else {
+ args.sign = FmtArgs::Sign::Unspec;
+ }
+
+ if( *s == '#' ) {
+ args.alternate = true;
+ s ++;
+ }
+ else {
+ //args.alternate = false;
+ }
+
+ if( *s == '0' ) {
+ args.zero_pad = true;
+ s ++;
+ }
+ else {
+ //args.zero_pad = false;
+ }
+
+ // Padded width
+ if( ::std::isdigit(*s) /*|| *s == '*'*/ ) {
+ unsigned int val = 0;
+ while( ::std::isdigit(*s) )
+ {
+ val *= 10;
+ val += *s - '0';
+ s ++;
+ }
+ args.width = val;
+
+ if( *s == '$' ) {
+ args.width_is_arg = true;
+ s ++;
+ }
+ else {
+ //args.width_is_arg = false;
+ }
+ }
+ // Precision
+ if( *s == '.' ) {
+ s ++;
+ // '*' - Use next argument
+ if( *s == '*' ) {
+ args.prec_is_arg = true;
+ if( next_free == n_free ) {
+ ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
+ }
+ args.prec = next_free + n_named;
+ next_free ++;
+ }
+ else {
+ unsigned int val = 0;
+ while( ::std::isdigit(*s) )
+ {
+ val *= 10;
+ val += *s - '0';
+ s ++;
+ }
+ args.prec = val;
+
+ if( *s == '$' ) {
+ args.prec_is_arg = true;
+ s ++;
+ }
+ else {
+ //args.prec_is_arg = false;
+ }
+ }
+ }
+
+ // Parse ident?
+ // - Lazy way is to just handle a single char and ensure that it is just a single char
+ if( s[0] != '}' && s[0] != '\0' && s[1] != '}' ) {
+ TODO(sp, "Parse formatting fragment at \"" << s << "\" (long type)");
+ }
+
+ switch(s[0])
+ {
+ case '\0':
+ ERROR(sp, E0000, "Unexpected end of formatting string");
+ default:
+ ERROR(sp, E0000, "Unknown formatting type specifier '" << *s << "'");
+ case '}': trait_name = "Display"; break;
+ case '?': s++; trait_name = "Debug" ; break;
+ case 'b': s++; trait_name = "Binary"; break;
+ case 'o': s++; trait_name = "Octal" ; break;
+ case 'x': s++; trait_name = "LowerHex"; break;
+ case 'X': s++; trait_name = "UpperHex"; break;
+ case 'p': s++; trait_name = "Pointer" ; break;
+ case 'e': s++; trait_name = "LowerExp"; break;
+ case 'E': s++; trait_name = "UpperExp"; break;
+ }
+ assert(*s == '}');
+ }
+ else {
+ if( *s != '}' )
+ ERROR(sp, E0000, "Malformed formatting fragment, unexpected " << *s);
+ // Otherwise, it's just a trivial Display call
+ trait_name = "Display";
+ }
+
+ // Set index if unspecified
+ if( index == ~0u )
+ {
+ if( next_free == n_free ) {
+ ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
+ }
+ index = next_free + n_named;
+ next_free ++;
+ }
+
+ frags.push_back( FmtFrag {
+ mv$(cur_literal),
+ index, trait_name,
+ mv$(args)
+ });
+ }
+ }
+
+ return ::std::make_tuple( mv$(frags), mv$(cur_literal) );
+ }
+}
+
class CFormatArgsExpander:
public ExpandProcMacro
{
@@ -22,21 +265,30 @@ class CFormatArgsExpander:
auto n = Parse_ExprVal(lex);
auto format_string = dynamic_cast<AST::ExprNode_String&>(*n).m_value;
- // TODO: Interpolated expression "tokens"
- ::std::map< ::std::string, TokenTree> named_args;
+ ::std::map< ::std::string, unsigned int> named_args_index;
+ ::std::vector<TokenTree> named_args;
::std::vector<TokenTree> free_args;
+ // - Parse the arguments
while( GET_TOK(tok, lex) == TOK_COMMA )
{
+ // - Named parameters
if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_EQUAL )
{
GET_CHECK_TOK(tok, lex, TOK_IDENT);
auto name = mv$(tok.str());
+
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+
auto expr_tt = Parse_TT_Expr(lex);
- named_args.insert( ::std::make_pair(mv$(name), mv$(expr_tt)) );
+ auto ins_rv = named_args_index.insert( ::std::make_pair(mv$(name), named_args.size()) );
+ if( ins_rv.second == false ) {
+ ERROR(sp, E0000, "Duplicate definition of named argument `" << ins_rv.first->first << "`");
+ }
+ named_args.push_back( mv$(expr_tt) );
}
+ // - Free parameters
else
{
auto expr_tt = Parse_TT_Expr(lex);
@@ -44,10 +296,44 @@ class CFormatArgsExpander:
}
}
- // TODO: Expand format_args!
+ // - Parse the format string
+ ::std::vector< FmtFrag> fragments;
+ ::std::string tail;
+ ::std::tie( fragments, tail ) = parse_format_string(sp, format_string, named_args_index, free_args.size());
+
+ // TODO: Properly expand format_args! (requires mangling to fit ::core::fmt::rt::v1)
+ // - For now, just emits the text with no corresponding format fragments
+
::std::vector<TokenTree> toks;
- toks.push_back( TokenTree(TOK_PAREN_OPEN) );
- toks.push_back( TokenTree(TOK_PAREN_CLOSE) );
+ {
+ // TODO: Figure out what path to use (::fmt, ::core::fmt, or ::std::fmt)
+
+ //toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
+ //toks.push_back( Token(TOK_IDENT, "std") ); //toks.push_back( Token(TOK_STRING, "core") );
+ toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
+ toks.push_back( Token(TOK_IDENT, "fmt") );
+ toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
+ toks.push_back( Token(TOK_IDENT, "Arguments") );
+ toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
+ toks.push_back( Token(TOK_IDENT, "new_v1") );
+ toks.push_back( TokenTree(TOK_PAREN_OPEN) );
+ {
+ toks.push_back( TokenTree(TOK_AMP) );
+ toks.push_back( TokenTree(TOK_SQUARE_OPEN) );
+ for(const auto& frag : fragments ) {
+ toks.push_back( Token(TOK_STRING, frag.leading_text) );
+ toks.push_back( TokenTree(TOK_COMMA) );
+ }
+ toks.push_back( TokenTree(TOK_SQUARE_CLOSE) );
+ toks.push_back( TokenTree(TOK_COMMA) );
+
+ toks.push_back( TokenTree(TOK_AMP) );
+ toks.push_back( TokenTree(TOK_SQUARE_OPEN) );
+ toks.push_back( TokenTree(TOK_SQUARE_CLOSE) );
+ }
+ toks.push_back( TokenTree(TOK_PAREN_CLOSE) );
+ }
+
return box$( TTStreamO(TokenTree(mv$(toks))) );
}
};
diff --git a/src/include/synext.hpp b/src/include/synext.hpp
index ae1c14f6..76b41996 100644
--- a/src/include/synext.hpp
+++ b/src/include/synext.hpp
@@ -4,93 +4,9 @@
#ifndef _SYNEXT_HPP_
#define _SYNEXT_HPP_
-#include "../ast/item.hpp"
-#include <span.hpp>
-
-class TypeRef;
-namespace AST {
- class Crate;
- class MetaItem;
- class Path;
-
- struct StructItem;
- struct TupleItem;
- struct EnumVariant;
-
- class Module;
- class Item;
-
- class Expr;
- class ExprNode;
- struct ExprNode_Match_Arm;
-
- class MacroInvocation;
-
- class ImplDef;
-}
-class TokenTree;
-class TokenStream;
-
-
-#include "../common.hpp" // for mv$ and other things
-#include <string>
-#include <memory>
-
-enum class AttrStage
-{
- EarlyPre,
- EarlyPost,
- LatePre,
- LatePost,
-};
-
-class ExpandDecorator
-{
- void unexpected(const Span& sp, const AST::MetaItem& mi, const char* loc_str) const;
-public:
- virtual AttrStage stage() const = 0;
-
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, AST::MacroInvocation& mac) const { unexpected(sp, mi, "macro invocation"); }
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
- // NOTE: To delete, set the type to `_`
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
- // NOTE: To delete, clear the name
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::StructItem& si) const { unexpected(sp, mi, "struct item"); }
- // NOTE: To delete, make the type invalid
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::TupleItem& si) const { unexpected(sp, mi, "tuple item"); }
- // NOTE: To delete, clear the name
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::EnumVariant& ev) const { unexpected(sp, mi, "enum variant"); }
-
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const { unexpected(sp, mi, "expression"); }
- // NOTE: To delete, clear the patterns vector
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& expr) const { unexpected(sp, mi, "match arm"); }
-};
-
-class ExpandProcMacro
-{
-public:
- virtual bool expand_early() const = 0;
-
- virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0;
-};
-
-#define STATIC_DECORATOR(ident, _handler_class) \
- struct register_##_handler_class##_c {\
- register_##_handler_class##_c() {\
- Register_Synext_Decorator( ident, ::std::unique_ptr<ExpandDecorator>(new _handler_class()) ); \
- } \
- } s_register_##_handler_class;
-#define STATIC_MACRO(ident, _handler_class) \
- struct register_##_handler_class##_c {\
- register_##_handler_class##_c() {\
- Register_Synext_Macro( ident, ::std::unique_ptr<ExpandProcMacro>(new _handler_class()) ); \
- } \
- } s_register_##_handler_class;
-
-extern void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<ExpandDecorator> handler);
-extern void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro> handler);
-
+#include "../common.hpp" // for LList
+#include "synext_decorator.hpp"
+#include "synext_macro.hpp"
extern void Expand_Expr(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> modstack, ::std::unique_ptr<AST::ExprNode>& node);
diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp
new file mode 100644
index 00000000..5ae1af53
--- /dev/null
+++ b/src/include/synext_decorator.hpp
@@ -0,0 +1,75 @@
+/*
+ */
+#pragma once
+#ifndef _SYNEXT_DECORATOR_HPP_
+#define _SYNEXT_DECORATOR_HPP_
+
+#include <string>
+#include <memory>
+#include <span.hpp>
+#include "../ast/item.hpp"
+
+class TypeRef;
+namespace AST {
+ class Crate;
+ class MetaItem;
+ class Path;
+
+ struct StructItem;
+ struct TupleItem;
+ struct EnumVariant;
+
+ class Module;
+ class Item;
+
+ class Expr;
+ class ExprNode;
+ struct ExprNode_Match_Arm;
+
+ class MacroInvocation;
+
+ class ImplDef;
+}
+
+enum class AttrStage
+{
+ EarlyPre,
+ EarlyPost,
+ LatePre,
+ LatePost,
+};
+
+class ExpandDecorator
+{
+ void unexpected(const Span& sp, const AST::MetaItem& mi, const char* loc_str) const;
+public:
+ virtual AttrStage stage() const = 0;
+
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, AST::MacroInvocation& mac) const { unexpected(sp, mi, "macro invocation"); }
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
+ // NOTE: To delete, set the type to `_`
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
+ // NOTE: To delete, clear the name
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::StructItem& si) const { unexpected(sp, mi, "struct item"); }
+ // NOTE: To delete, make the type invalid
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::TupleItem& si) const { unexpected(sp, mi, "tuple item"); }
+ // NOTE: To delete, clear the name
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::EnumVariant& ev) const { unexpected(sp, mi, "enum variant"); }
+
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const { unexpected(sp, mi, "expression"); }
+ // NOTE: To delete, clear the patterns vector
+ virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& expr) const { unexpected(sp, mi, "match arm"); }
+};
+
+#define STATIC_DECORATOR(ident, _handler_class) \
+ struct register_##_handler_class##_c {\
+ register_##_handler_class##_c() {\
+ Register_Synext_Decorator( ident, ::std::unique_ptr<ExpandDecorator>(new _handler_class()) ); \
+ } \
+ } s_register_##_handler_class;
+
+extern void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<ExpandDecorator> handler);
+
+#endif
+
diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp
new file mode 100644
index 00000000..1aa7fef5
--- /dev/null
+++ b/src/include/synext_macro.hpp
@@ -0,0 +1,40 @@
+/*
+ */
+#pragma once
+#ifndef _SYNEXT_MACRO_HPP_
+#define _SYNEXT_MACRO_HPP_
+
+//#include "../common.hpp" // for mv$ and other things
+#include <string>
+#include <memory>
+#include <span.hpp>
+
+class TypeRef;
+namespace AST {
+ class Crate;
+ class Module;
+}
+class TokenTree;
+class TokenStream;
+
+
+
+class ExpandProcMacro
+{
+public:
+ virtual bool expand_early() const = 0;
+
+ virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0;
+};
+
+#define STATIC_MACRO(ident, _handler_class) \
+ struct register_##_handler_class##_c {\
+ register_##_handler_class##_c() {\
+ Register_Synext_Macro( ident, ::std::unique_ptr<ExpandProcMacro>(new _handler_class()) ); \
+ } \
+ } s_register_##_handler_class;
+
+extern void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro> handler);
+
+#endif
+