diff options
author | John Hodge <tpg@mutabah.net> | 2016-06-08 12:37:51 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-06-08 12:37:51 +0800 |
commit | 40071822728499b9028400ddac3cd32fb884b2a0 (patch) | |
tree | beabbf632622601b307beb8308f1098e9da91a15 | |
parent | d91e9415d3a3cd4c9cc5bfcee548d6b3b98867f5 (diff) | |
download | mrust-40071822728499b9028400ddac3cd32fb884b2a0.tar.gz |
Expand format_args! - Parse and (partially) emit
-rw-r--r-- | src/expand/format_args.cpp | 300 | ||||
-rw-r--r-- | src/include/synext.hpp | 90 | ||||
-rw-r--r-- | src/include/synext_decorator.hpp | 75 | ||||
-rw-r--r-- | src/include/synext_macro.hpp | 40 |
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 + |