annotate qt/qtd/ctfe/Format.d @ 288:f9559a957be9 signals

new signals and slots implementation
author eldar
date Sun, 08 Nov 2009 19:28:01 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
288
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
1 /**
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
2 * Compile-Time String Formatting.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
3 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
4 * Authors: Daniel Keep <daniel.keep@gmail.com>
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
5 * Copyright: See LICENSE.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
6 */
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
7 module qt.qtd.ctfe.Format;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
8
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
9 //debug = gb_Format_verbose;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
10
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
11 import Integer = qt.qtd.ctfe.Integer;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
12 import String = qt.qtd.ctfe.String;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
13 import Tuple = qt.qtd.util.Tuple;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
14
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
15 private
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
16 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
17 string stringify(Args...)(size_t index, int alignment,
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
18 string opt, Args args)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
19 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
20 if( index >= args.length )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
21 return "{invalid index " ~ Integer.format_ctfe(index) ~ "}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
22
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
23 if( alignment != 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
24 return "{non-zero alignments not supported yet}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
25
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
26 foreach( i,_ ; Args )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
27 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
28 if( i == index )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
29 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
30 static if( is( Args[i] == char ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
31 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
32 string r;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
33 r ~= args[i];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
34 return r;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
35 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
36 else static if( is( Args[i] : long ) || is( Args[i] : ulong ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
37 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
38 int base = 10;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
39 string prefix = "";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
40
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
41 if( opt == "x" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
42 base = 16;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
43
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
44 else if( opt == "xx" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
45 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
46 base = 16;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
47 prefix = "0x";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
48 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
49 else if( opt == "o" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
50 base = 8;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
51
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
52 else if( opt == "b" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
53 base = 2;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
54
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
55 return prefix ~ Integer.format_ctfe(args[i], base);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
56 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
57 else static if( is( Args[i] : string ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
58 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
59 if( opt == "x" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
60 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
61 return String.hexify_ctfe(args[i][]);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
62 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
63
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
64 if( opt == "q" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
65 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
66 return String.escape_ctfe(args[i][]);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
67 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
68
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
69 if( opt == "l" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
70 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
71 return Integer.format_ctfe(args[i].length);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
72 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
73
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
74 // If you don't slice, then the CALLER has to slice the
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
75 // string, otherwise CTFE barfs.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
76 return args[i][];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
77 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
78 else static if( is( Args[i] Elem : Elem[] ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
79 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
80 if( opt == "l" )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
81 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
82 return Integer.format_ctfe(args[i].length);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
83 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
84
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
85 string r = "[";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
86 foreach( ei, e ; args[i][] )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
87 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
88 if( ei != 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
89 r ~= ", ";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
90 r ~= stringify(0, alignment, opt, e);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
91 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
92 r ~= "]";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
93 return r;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
94 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
95 else
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
96 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
97 return "{cannot stringify "~Args[i].stringof~"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
98 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
99 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
100 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
101
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
102 assert(false);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
103 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
104
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
105 version( Unittest )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
106 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
107 static assert( stringify(0, 0, "", 0) == "0" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
108 static assert( stringify(0, 0, "", 1, -2, "abc") == "1" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
109 static assert( stringify(1, 0, "", 1, -2, "abc") == "-2" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
110 static assert( stringify(2, 0, "", 1, -2, "abc") == "abc" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
111
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
112 static assert( stringify(0, 0, "x", "abc") == `616263` );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
113 static assert( stringify(0, 0, "q", "abc") == `"abc"` );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
114 static assert( stringify(0, 0, "l", "abc") == `3` );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
115
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
116 static assert( stringify(0, 0, "x", 0x4a) == "4a" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
117
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
118 static assert( stringify(0, 0, "", [1,2,3]) == "[1, 2, 3]" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
119 static assert( stringify(0, 0, "l", [1,2,3]) == "3" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
120 static assert( stringify(0, 0, "x", [9,10]) == "[9, a]" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
121 static assert( stringify(0, 0, "", ["a","b"]) == "[a, b]" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
122 static assert( stringify(0, 0, "q", ["a","b"]) == "[\"a\", \"b\"]" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
123
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
124 static assert( stringify(0, 0, "", 'a') == "a" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
125 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
126 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
127
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
128 /**
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
129 * Substitutes a set of arguments into a template string.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
130 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
131 * The template string allows for the following escape forms:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
132 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
133 * - $$ -- Literal dollar.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
134 * - $* -- Next argument.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
135 * - $n -- nth argument; 0-9 only.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
136 * - ${} -- Next argument.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
137 * - ${:f} -- Next argument, using format options "f".
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
138 * - ${n} -- nth argument.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
139 * - ${n:f} -- nth argument, using format options "f".
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
140 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
141 * formatNamed allows the use of named arguments (given as alternating
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
142 * name,value pairs), but disallows "next" argument and indexed forms.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
143 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
144 * Eventually, alignment and named arguments will be supported.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
145 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
146 * Supported formatting options are:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
147 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
148 * Integers:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
149 * - x -- format integer in hexadecimal.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
150 * - o -- format integer in octal.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
151 * - b -- format integer in binary.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
152 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
153 * Strings:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
154 * - q -- quotes the string as a literal.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
155 * - x -- formats as hexadecimal data.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
156 * - l -- length of the string in decimal.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
157 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
158 * Arrays:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
159 * - l -- length of the array in decimal.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
160 * - Other options are used to control element formatting.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
161 *
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
162 * Params:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
163 * tmpl = template string.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
164 * args = arguments to substitute.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
165 * Returns:
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
166 * formatted string.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
167 */
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
168
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
169 string format_ctfe(Args...)(string tmpl, Args args)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
170 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
171 string r = "";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
172 int argPos = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
173
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
174 while( tmpl.length > 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
175 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
176 bool inExp = false;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
177
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
178 // Look for a $
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
179 foreach( i,c ; tmpl )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
180 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
181 if (c == '$')
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
182 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
183 inExp = true;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
184 r ~= tmpl[0..i];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
185 tmpl = tmpl[i+1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
186 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
187 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
188 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
189
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
190 // If we didn't find a $, it's because we hit the end of the template.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
191 if( !inExp )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
192 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
193 r ~= tmpl;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
194 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
195 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
196
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
197 // So we're in an expansion/substitution.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
198
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
199 debug(gb_Format_verbose) r ~= "{in exp}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
200
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
201 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
202 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
203 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
204 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
205 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
206
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
207 // c is the next character, whilst tmpl is everything left in the
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
208 // template string.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
209 char c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
210 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
211
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
212 // $$ - escaped $.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
213 if( c == '$' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
214 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
215 debug(gb_Format_verbose) r ~= "{escaped $}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
216 r ~= '$';
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
217 continue;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
218 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
219
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
220 // $n - shortcut for ${n}.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
221 if( '0' <= c && c <= '9' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
222 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
223 debug(gb_Format_verbose) r ~= "{shorthand index}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
224 r ~= stringify(c-'0', 0, "", args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
225 continue;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
226 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
227
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
228 // $* - shortcut for ${}
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
229 if( c == '*' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
230 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
231 debug(gb_Format_verbose) r ~= "{shorthand next}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
232 r ~= stringify(argPos++, 0, "", args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
233 continue;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
234 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
235
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
236 // This means we got a $ followed by something unexpected.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
237 if( c != '{' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
238 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
239 r ~= "{malformed substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
240 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
241 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
242
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
243 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
244 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
245 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
246 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
247 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
248
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
249 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
250 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
251 r ~= "{parse complex at '";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
252 r ~= c;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
253 r ~= "':\"" ~ tmpl ~ "\"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
254 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
255
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
256 // NOTE: We haven't updated c and tmpl yet.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
257
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
258 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
259 // arg will contain the index of the argument the user wanted
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
260 // substituted.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
261 size_t arg = size_t.max;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
262 // fmt will contain any additional formatting options.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
263 string fmt = "";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
264
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
265 // If we didn't get a : or }, that means we expect an index.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
266 if( !( tmpl[0] == ':' || tmpl[0] == '}' ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
267 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
268 // So parse it.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
269 auto used = Integer.parse_ctfe!(size_t)(tmpl, true);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
270
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
271 if( used == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
272 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
273 debug(gb_Format_verbose) r ~= "{used zero of \""~tmpl~"\"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
274 r ~= "{invalid argument index}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
275 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
276 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
277
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
278 arg = Integer.parse_ctfe!(size_t)(tmpl);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
279 tmpl = tmpl[used..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
280
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
281 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
282 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
283 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
284 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
285 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
286 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
287 else
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
288 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
289 // Otherwise, the index was elided, which means we want to use
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
290 // the index of the "next" argument.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
291 arg = argPos;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
292 ++ argPos;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
293 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
294
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
295 c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
296 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
297
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
298 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
299 r ~= "{index " ~ Integer.format_ctfe(arg) ~ "}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
300
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
301 // If c is :, then we've got formatting options to parse
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
302
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
303 if( c == ':' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
304 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
305 debug(gb_Format_verbose) r ~= "{fmt string}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
306
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
307 // Look for the closing }.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
308 size_t len = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
309 foreach( i,d ; tmpl )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
310 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
311 if( d == '}' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
312 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
313 len = i;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
314 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
315 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
316 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
317 if( len == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
318 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
319 r ~= "{malformed format}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
320 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
321 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
322 fmt = tmpl[0..len];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
323 tmpl = tmpl[len..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
324
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
325 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
326 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
327 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
328 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
329 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
330
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
331 c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
332 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
333 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
334
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
335 // At this point, we should have the closing }. If not, someone's
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
336 // screwed up.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
337 if( c != '}' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
338 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
339 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
340 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
341 r ~= "{expected closing; got '";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
342 r ~= c;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
343 r ~= "':\"" ~ tmpl ~ "\"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
344 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
345 r ~= "{malformed substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
346 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
347 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
348
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
349 // Stringify that bugger.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
350 r ~= stringify(arg, 0, fmt, args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
351
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
352 // When we fall off the end here, we'll continue with the
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
353 // remainder of tmpl, unless it's empty in which case we're
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
354 // finished.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
355 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
356 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
357
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
358 return r;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
359 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
360
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
361 version( Unittest )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
362 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
363 static assert(format_ctfe("A: $$", "foo"[]) == "A: $");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
364 static assert(format_ctfe("B: a $$ c", "b"[]) == "B: a $ c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
365
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
366 static assert(format_ctfe("C: ${}", "foo"[]) == "C: foo");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
367 static assert(format_ctfe("D: a ${} c", "b"[]) == "D: a b c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
368
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
369 static assert(format_ctfe("E: $0", "foo"[]) == "E: foo");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
370 static assert(format_ctfe("F: a $0 c", "b"[]) == "F: a b c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
371
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
372 static assert(format_ctfe("G: $*", "foo"[]) == "G: foo");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
373 static assert(format_ctfe("H: a $* c", "b"[]) == "H: a b c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
374
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
375 static assert(format_ctfe("I: ${0}", "foo"[]) == "I: foo");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
376 static assert(format_ctfe("J: a ${0} c", "b"[]) == "J: a b c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
377
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
378 static assert(format_ctfe("K: ${} ${} ${}", 1, -2, "c"[]) == "K: 1 -2 c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
379 static assert(format_ctfe("L: $* $* $*", 1, -2, "c"[]) == "L: 1 -2 c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
380 static assert(format_ctfe("M: $0 $1 $2", 1, -2, "c"[]) == "M: 1 -2 c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
381 static assert(format_ctfe("N: ${0} ${1} ${2}", 1, -2, "c"[]) == "N: 1 -2 c");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
382
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
383 static assert(format_ctfe("O: ${2} ${0} ${1}", 1, -2, "c"[]) == "O: c 1 -2");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
384
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
385 static assert(format_ctfe("P: ${:x} ${0:x} ${0:o} ${0:b}", 42) == "P: 2a 2a 52 101010");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
386
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
387 static assert(format_ctfe("Q: ${0} ${0:q} ${0:x}", "abc"[]) == "Q: abc \"abc\" 616263");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
388 static assert(format_ctfe("R: ${0} ${0:q}", ["a","b","c"][]) == "R: [a, b, c] [\"a\", \"b\", \"c\"]");
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
389
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
390 const TORTURE_TMPL = `
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
391 struct $*Enum
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
392 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
393 const Name = ${0:q};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
394 const string[${:l}] Members = ${1:q};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
395
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
396 ${2} value()
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
397 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
398 return ${3:xx};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
399 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
400 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
401 `[];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
402
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
403 const TORTURE_EXPECTED = `
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
404 struct FooEnum
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
405 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
406 const Name = "Foo";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
407 const string[3] Members = ["bar", "quxx", "zyzzy"];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
408
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
409 int value()
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
410 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
411 return 0x42;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
412 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
413 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
414 `[];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
415
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
416 const TORTURE_ACTUAL = format_ctfe(TORTURE_TMPL,
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
417 "Foo"[], ["bar"[],"quxx","zyzzy"][],
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
418 "int"[], 0x42);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
419
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
420 static assert( TORTURE_EXPECTED == TORTURE_ACTUAL );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
421 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
422
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
423 private
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
424 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
425 size_t findIndexByName(Args...)(string name, Args args)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
426 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
427 foreach( i ; Tuple.Sequence!(0, Args.length, 2) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
428 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
429 static if( !is( Args[i] : string ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
430 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
431 static assert(false, "expected string for argument "
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
432 ~ Integer.format_ctfe(i) ~ " in " ~ Args.stringof
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
433 ~ " not " ~ Args[i].stringof);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
434 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
435 if( name == args[i][] )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
436 return i+1;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
437 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
438 return size_t.max;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
439 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
440
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
441 version( Unittest )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
442 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
443 static assert( findIndexByName("a", "a", 0, "b", 1) == 1 );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
444 static assert( findIndexByName("b", "a", 0, "b", 1) == 3 );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
445 static assert( findIndexByName("c", "a", 0, "b", 1) == size_t.max );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
446 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
447 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
448
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
449 /// ditto
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
450
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
451 string formatNamed_ctfe(Args...)(string tmpl, Args args)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
452 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
453 string r = "";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
454 int argPos = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
455
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
456 while( tmpl.length > 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
457 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
458 bool inExp = false;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
459
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
460 // Look for a $
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
461 foreach( i,c ; tmpl )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
462 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
463 if (c == '$')
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
464 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
465 inExp = true;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
466 r ~= tmpl[0..i];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
467 tmpl = tmpl[i+1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
468 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
469 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
470 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
471
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
472 // If we didn't find a $, it's because we hit the end of the template.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
473 if( !inExp )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
474 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
475 r ~= tmpl;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
476 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
477 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
478
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
479 // So we're in an expansion/substitution.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
480
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
481 debug(gb_Format_verbose) r ~= "{in exp}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
482
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
483 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
484 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
485 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
486 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
487 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
488
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
489 // c is the next character, whilst tmpl is everything left in the
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
490 // template string.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
491 char c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
492 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
493
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
494 // $$ - escaped $.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
495 if( c == '$' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
496 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
497 debug(gb_Format_verbose) r ~= "{escaped $}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
498 r ~= '$';
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
499 continue;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
500 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
501
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
502 // $a... - shortcut for $a...
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
503 if( String.isIdentStartChar_ctfe(c) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
504 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
505 debug(gb_Format_verbose) r ~= "{shorthand name}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
506 size_t i = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
507 while( i < tmpl.length )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
508 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
509 if( !String.isIdentChar_ctfe(tmpl[i]) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
510 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
511 ++ i;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
512 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
513 string name = c ~ tmpl[0..i];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
514 tmpl = tmpl[i..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
515 r ~= stringify(findIndexByName(name, args), 0, "", args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
516 continue;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
517 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
518
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
519 // This means we got a $ followed by something unexpected.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
520 if( c != '{' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
521 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
522 r ~= "{malformed substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
523 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
524 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
525
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
526 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
527 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
528 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
529 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
530 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
531
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
532 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
533 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
534 r ~= "{parse complex at '";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
535 r ~= c;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
536 r ~= "':\"" ~ tmpl ~ "\"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
537 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
538
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
539 // NOTE: We haven't updated c and tmpl yet.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
540
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
541 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
542 // arg will contain the index of the argument the user wanted
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
543 // substituted.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
544 size_t arg = size_t.max;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
545 // fmt will contain any additional formatting options.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
546 string fmt = "";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
547
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
548 // If we didn't get a : or }, that means we expect a name.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
549 if( !( tmpl[0] == ':' || tmpl[0] == '}' ) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
550 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
551 // So parse it.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
552 size_t i = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
553 while( i < tmpl.length )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
554 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
555 if( !String.isIdentChar_ctfe(tmpl[i]) )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
556 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
557 ++ i;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
558 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
559 string name = tmpl[0..i];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
560 tmpl = tmpl[i..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
561
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
562 arg = findIndexByName(name, args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
563
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
564 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
565 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
566 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
567 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
568 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
569 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
570 else
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
571 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
572 // Otherwise, the name was elided. Kaboom!
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
573 r ~= "{substitution missing name}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
574 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
575 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
576
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
577 c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
578 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
579
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
580 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
581 r ~= "{index " ~ Integer.format_ctfe(arg) ~ "}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
582
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
583 // If c is :, then we've got formatting options to parse
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
584
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
585 if( c == ':' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
586 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
587 debug(gb_Format_verbose) r ~= "{fmt string}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
588
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
589 // Look for the closing }.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
590 size_t len = 0;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
591 foreach( i,d ; tmpl )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
592 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
593 if( d == '}' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
594 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
595 len = i;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
596 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
597 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
598 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
599 if( len == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
600 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
601 r ~= "{malformed format}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
602 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
603 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
604 fmt = tmpl[0..len];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
605 tmpl = tmpl[len..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
606
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
607 debug(gb_Format_verbose) r ~= "{fmt:"~fmt~"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
608
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
609 if( tmpl.length == 0 )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
610 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
611 r ~= "{unterminated substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
612 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
613 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
614
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
615 c = tmpl[0];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
616 tmpl = tmpl[1..$];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
617 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
618
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
619 // At this point, we should have the closing }. If not, someone's
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
620 // screwed up.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
621 if( c != '}' )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
622 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
623 debug(gb_Format_verbose)
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
624 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
625 r ~= "{expected closing; got '";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
626 r ~= c;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
627 r ~= "':\"" ~ tmpl ~ "\"}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
628 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
629 r ~= "{malformed substitution}";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
630 break;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
631 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
632
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
633 // Stringify that bugger.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
634 r ~= stringify(arg, 0, fmt, args);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
635
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
636 // When we fall off the end here, we'll continue with the
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
637 // remainder of tmpl, unless it's empty in which case we're
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
638 // finished.
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
639 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
640 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
641
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
642 return r;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
643 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
644
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
645 version( Unittest )
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
646 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
647 static assert( formatNamed_ctfe("A: $$", "a"[], 0, "b"[], 1) == "A: $" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
648 static assert( formatNamed_ctfe("B: $a", "a"[], 0, "b"[], 1) == "B: 0" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
649 static assert( formatNamed_ctfe("C: $b", "a"[], 0, "b"[], 1) == "C: 1" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
650
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
651 static assert( formatNamed_ctfe("D: ${a}", "a"[], 0, "b"[], 1) == "D: 0" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
652 static assert( formatNamed_ctfe("E: ${b}", "a"[], 0, "b"[], 1) == "E: 1" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
653
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
654 static assert( formatNamed_ctfe("F: $foo$bar", "foo"[], 0, "bar"[], 1) == "F: 01" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
655 static assert( formatNamed_ctfe("G: ${foo}${bar}", "foo"[], 0, "bar"[], 1) == "G: 01" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
656
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
657 static assert( formatNamed_ctfe("H: ${foo:x}${bar:xx}", "foo"[], 0, "bar"[], 1) == "H: 00x1" );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
658
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
659 const TORTURE_NAMED_TMPL = `
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
660 struct ${name}Enum
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
661 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
662 const Name = ${name:q};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
663 const string[${members:l}] Members = ${members:q};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
664
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
665 ${retType} value()
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
666 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
667 return ${value:xx};
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
668 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
669 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
670 `[];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
671
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
672 const TORTURE_NAMED_EXPECTED = `
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
673 struct FooEnum
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
674 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
675 const Name = "Foo";
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
676 const string[3] Members = ["bar", "quxx", "zyzzy"];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
677
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
678 int value()
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
679 {
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
680 return 0x42;
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
681 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
682 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
683 `[];
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
684
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
685 const TORTURE_NAMED_ACTUAL = formatNamed_ctfe(TORTURE_NAMED_TMPL,
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
686 "name"[], "Foo"[],
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
687 "members"[], ["bar"[],"quxx","zyzzy"][],
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
688 "retType"[], "int"[],
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
689 "value"[], 0x42);
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
690
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
691 static assert( TORTURE_NAMED_EXPECTED == TORTURE_NAMED_ACTUAL );
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
692 }
f9559a957be9 new signals and slots implementation
eldar
parents:
diff changeset
693