Wed, 26 Feb 2014 07:36:14 +0200
- now uses a variadic template formatter instead of a macro
src/Format.cc | file | annotate | diff | comparison | revisions | |
src/Format.h | file | annotate | diff | comparison | revisions | |
src/Main.cc | file | annotate | diff | comparison | revisions | |
src/Types.h | file | annotate | diff | comparison | revisions |
--- a/src/Format.cc Sun Feb 23 17:45:34 2014 +0200 +++ b/src/Format.cc Wed Feb 26 07:36:14 2014 +0200 @@ -33,30 +33,23 @@ // ============================================================================= // -static void DrawPosition (const String& fmt, int pos) +static void FormatError (String fmtstr, const String errdescribe, int pos) { - String rep (fmt); - rep.Replace ("\n", "↵"); - rep.Replace ("\t", "⇥"); - - fprintf (stderr, "%s\n", rep.CString()); + fmtstr.Replace ("\n", " "); + fmtstr.Replace ("\t", " "); + String errmsg ("With format string:\n" + fmtstr + "\n"); for (int x = 0; x < pos; ++x) - fprintf (stderr, "-"); + errmsg += "-"; - fprintf (stderr, "^\n"); + errmsg += "^\n" + errdescribe; + throw std::logic_error (errmsg.STDString()); } // ============================================================================= // -String FormatArgs (const List<FormatArgument>& args) +String FormatArgs (const String& fmtstr, const std::vector<String>& args) { - const String& fmtstr = args[0].AsString(); - assert (args.Size() >= 1); - - if (args.Size() == 1) - return args[0].AsString(); - String fmt = fmtstr; String out; int pos = 0; @@ -81,33 +74,26 @@ } if (!isdigit (fmt[pos + ofs])) - { - fprintf (stderr, "bad format string, expected digit with optional " - "modifier after '%%':\n"); - DrawPosition (fmt, pos); - return fmt; - } + FormatError (fmtstr, "bad format string, expected digit with optional " + "modifier after '%%'", pos); int i = fmt[pos + ofs] - '0'; - if (i >= args.Size()) - { - fprintf (stderr, "format arg #%d used but not defined: %s\n", i, fmtstr.CString()); - return fmt; - } + if (i > static_cast<signed> (args.size())) + FormatError (fmtstr, String ("Format argument #") + i + " used but not defined.", pos); - String repl = args[i].AsString(); + String replacement = args[i - 1]; switch (mod) { - case 's': repl = (repl == "1") ? "" : "s"; break; - case 'd': repl.SPrintf ("%d", repl[0]); break; - case 'x': repl.SPrintf ("0x%X", repl.ToLong()); break; + case 's': replacement = (replacement == "1") ? "" : "s"; break; + case 'd': replacement.SPrintf ("%d", replacement[0]); break; + case 'x': replacement.SPrintf ("0x%X", replacement.ToLong()); break; default: break; } - fmt.Replace (pos, 1 + ofs, repl); - pos += repl.Length(); + fmt.Replace (pos, 1 + ofs, replacement); + pos += replacement.Length(); } return fmt; @@ -115,15 +101,7 @@ // ============================================================================= // -void PrintArgs (FILE* fp, const List<FormatArgument>& args) -{ - String out = FormatArgs (args); - fprintf (fp, "%s", out.CString()); -} - -// ============================================================================= -// -void DoError (String msg) +void Error (String msg) { Lexer* lx = Lexer::GetCurrentLexer(); String fileinfo; @@ -134,5 +112,5 @@ fileinfo = Format ("%1:%2:%3: ", tk->file, tk->line, tk->column); } - throw ScriptError (fileinfo + msg); + throw std::runtime_error (fileinfo + msg); }
--- a/src/Format.h Sun Feb 23 17:45:34 2014 +0200 +++ b/src/Format.h Wed Feb 26 07:36:14 2014 +0200 @@ -35,20 +35,11 @@ class FormatArgument { public: - FormatArgument (const String& a) : - mText (a) {} - - FormatArgument (char a) : - mText (a) {} - - FormatArgument (int a) : - mText (String::FromNumber (a)) {} - - FormatArgument (long a) : - mText (String::FromNumber (a)) {} - - FormatArgument (const char* a) : - mText (a) {} + FormatArgument (const String& a) : mText (a) {} + FormatArgument (char a) : mText (a) {} + FormatArgument (int a) : mText (String::FromNumber (a)) {} + FormatArgument (long a) : mText (String::FromNumber (a)) {} + FormatArgument (const char* a) : mText (a) {} FormatArgument (void* a) { @@ -90,29 +81,6 @@ String mText; }; -template<class T> String custom_format (T a, const char* fmtstr) -{ - String out; - out.SPrintf (fmtstr, a); - return out; -} - -String FormatArgs (const List<FormatArgument>& args); -void PrintArgs (FILE* fp, const List<FormatArgument>& args); -void DoError (String msg); - -#ifndef IN_IDE_PARSER -# define Format(...) FormatArgs ({__VA_ARGS__}) -# define PrintTo(A, ...) PrintArgs (A, {__VA_ARGS__}) -# define Print(...) PrintArgs (stdout, {__VA_ARGS__}) -# define Error(...) DoError (Format (__VA_ARGS__)) -#else -String Format (void, ...); -void PrintTo (FILE* fp, ...); -void Print (void, ...); -void Error (void, ...); -#endif - #ifndef IN_IDE_PARSER # ifdef DEBUG # define devf(...) PrintTo (stderr, __VA_ARGS__) @@ -129,4 +97,135 @@ void dvalof (void a); #endif // IN_IDE_PARSER + +/** + * Formats the given string with the given args. + * + * @param fmtstr Formatter string to process. + * @param args Args to format with the string. + * @see format() + */ +String FormatArgs (const String& fmtstr, const std::vector<String>& args); + +/** + * Expands the given arguments into a vector of strings. + * + * @param data Where to insert the strings. + * @param arg First argument to process + * @param rest... Rest of the arguments. + */ +template<typename T, typename... RestTypes> +void ExpandFormatArguments (std::vector<String>& data, const T& arg, const RestTypes& ... rest) +{ + data.push_back (FormatArgument (arg).AsString()); + ExpandFormatArguments (data, rest...); +} + +/** + * This is an overload of @c ExpandFormatArguments for end-of-args support. + */ +static void ExpandFormatArguments (std::vector<String>& data) __attribute__ ( (unused)); +static void ExpandFormatArguments (std::vector<String>& data) +{ + (void) data; +} + +/** + * Formats the given formatter string and args and returns the string. + * This is essentially a modernized sprintf. + * + * Args in the format string take the form %n where n is a digit. The argument + * will be expanded to the nth argument passed. This is essentially Qt's + * QString::arg() syntax. Note: %0 is invalid. + * + * Arguments can be passed a modifier which takes the form of a character + * just before the digit. Currently supported modifiers are s, d and x. + * + * - s: The argument will expand into "s" if it would've not expanded into "1" + * otherwise. If it would have expanded into "1" it will expand into an + * empty string. + * + * - d: The argument expands into the numeric form of the first character of + * its previous expansion. Use this to get numeric forms of @c char + * arguments. + * + * - x: The numeric argument will be represented in hexadecimal notation. This + * will work if the argument is a string representing a number. If the + * argument did not expand into a number in the first place, 0 is used + * (and 0x0 is printed). + * + * @param fmtstr Formatter string to process + * @param raw_args Arguments for the formatter string. + * @return the formatted string. + * @see Print + * @see PrintTo + */ +template<typename... argtypes> +String Format (const String& fmtstr, const argtypes&... raw_args) +{ + std::vector<String> args; + ExpandFormatArguments (args, raw_args...); + assert (args.size() == sizeof... (raw_args)); + return FormatArgs (fmtstr, args); +} + +/** + * This is an overload of @c Format where no arguments are supplied. + * @return the formatter string as-is. + */ +static String Format (const String& fmtstr) __attribute__ ( (unused)); +static String Format (const String& fmtstr) +{ + return fmtstr; +} + +/** + * Processes the given formatter string using @c Format and prints it to the + * specified file pointer. + * + * @param fp File pointer to print the formatted string to + * @param fmtstr Formatter string for @c Format + * @param args Arguments for @c fmtstr + */ +template<typename... argtypes> +void PrintTo (FILE* fp, const String& fmtstr, const argtypes&... args) +{ + fprintf (fp, "%s", Format (fmtstr, args...).c_str()); +} + +/** + * Processes the given formatter string using @c Format and prints the result to + * @c stdout. + * + * @param fmtstr Formatter string for @c Format + * @param args Arguments for @c fmtstr + */ +template<typename... argtypes> +void Print (const String& fmtstr, const argtypes&... args) +{ + PrintTo (stdout, fmtstr, args...); +} + +/** + * Throws an std::runtime_error with the processed formatted string. The program + * execution terminates after a call to this function as the exception is first + * caught in @c main which prints the error to stderr and then exits. + * + * @param fmtstr The formatter string of the error. + * @param args The args to the formatter string. + * @see Format + */ +template<typename... argtypes> +void Error (const String& fmtstr, const argtypes&... args) +{ + Error (Format (fmtstr, args...)); +} + +/** + * An overload of @c Error with no string formatting in between. + * + * @param msg The error message. + */ +void Error (String msg); + #endif // BOTC_FORMAT_H
--- a/src/Main.cc Sun Feb 23 17:45:34 2014 +0200 +++ b/src/Main.cc Wed Feb 26 07:36:14 2014 +0200 @@ -112,7 +112,7 @@ } catch (std::exception& e) { - PrintTo (stderr, "error: %1\n", e.what()); + fprintf (stderr, "error: %s\n", e.what()); return 1; } }
--- a/src/Types.h Sun Feb 23 17:45:34 2014 +0200 +++ b/src/Types.h Wed Feb 26 07:36:14 2014 +0200 @@ -65,23 +65,6 @@ // ============================================================================= // -class ScriptError : public std::exception -{ - public: - ScriptError (const String& msg) : - mMsg (msg) {} - - inline const char* what() const throw() - { - return mMsg; - } - - private: - String mMsg; -}; - -// ============================================================================= -// // Get absolute value of @a // template<class T> inline T abs (T a)