root/trunk/minid/stringlib.d

Revision 412, 12.7 kB (checked in by JarrettBillingsley, 1 month ago)

MiniD's int type is now defined as a 64-bit integer. Also the beginnings of the Vector object are in the base library.

Line 
1 /******************************************************************************
2 License:
3 Copyright (c) 2008 Jarrett Billingsley
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the
7 use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it freely,
11 subject to the following restrictions:
12
13     1. The origin of this software must not be misrepresented; you must not
14     claim that you wrote the original software. If you use this software in a
15     product, an acknowledgment in the product documentation would be
16     appreciated but is not required.
17
18     2. Altered source versions must be plainly marked as such, and must not
19     be misrepresented as being the original software.
20
21     3. This notice may not be removed or altered from any source distribution.
22 ******************************************************************************/
23
24 module minid.stringlib;
25
26 import Float = tango.text.convert.Float;
27 import Integer = tango.text.convert.Integer;
28 import tango.core.Array;
29 import tango.text.Util;
30 import Uni = tango.text.Unicode;
31
32 import minid.ex;
33 import minid.interpreter;
34 import minid.types;
35 import minid.utils;
36
37 struct StringLib
38 {
39 static:
40     public void init(MDThread* t)
41     {
42         pushGlobal(t, "modules");
43         field(t, -1, "customLoaders");
44
45         newFunction(t, function uword(MDThread* t, uword numParams)
46         {
47             newFunction(t, &join, "join"); newGlobal(t, "join");
48
49             newNamespace(t, "string");
50                     newFunction(t, &iterator,        "iterator");
51                     newFunction(t, &iteratorReverse, "iteratorReverse");
52                 newFunction(t, &opApply,     "opApply", 2);  fielda(t, -2, "opApply");
53
54                 newFunction(t, &toInt,       "toInt");       fielda(t, -2, "toInt");
55                 newFunction(t, &toFloat,     "toFloat");     fielda(t, -2, "toFloat");
56                 newFunction(t, &compare,     "compare");     fielda(t, -2, "compare");
57 //              newFunction(t, &icompare,    "icompare");    fielda(t, -2, "icompare");
58                 newFunction(t, &find,        "find");        fielda(t, -2, "find");
59 //              newFunction(t, &ifind,       "ifind");       fielda(t, -2, "ifind");
60                 newFunction(t, &rfind,       "rfind");       fielda(t, -2, "rfind");
61 //              newFunction(t, &irfind,      "irfind");      fielda(t, -2, "irfind");
62                 newFunction(t, &toLower,     "toLower");     fielda(t, -2, "toLower");
63                 newFunction(t, &toUpper,     "toUpper");     fielda(t, -2, "toUpper");
64                 newFunction(t, &repeat,      "repeat");      fielda(t, -2, "repeat");
65                 newFunction(t, &reverse,     "reverse");     fielda(t, -2, "reverse");
66                 newFunction(t, &split,       "split");       fielda(t, -2, "split");
67                 newFunction(t, &splitLines,  "splitLines");  fielda(t, -2, "splitLines");
68                 newFunction(t, &strip,       "strip");       fielda(t, -2, "strip");
69                 newFunction(t, &lstrip,      "lstrip");      fielda(t, -2, "lstrip");
70                 newFunction(t, &rstrip,      "rstrip");      fielda(t, -2, "rstrip");
71                 newFunction(t, &replace,     "replace");     fielda(t, -2, "replace");
72                 newFunction(t, &startsWith,  "startsWith");  fielda(t, -2, "startsWith");
73                 newFunction(t, &endsWith,    "endsWith");    fielda(t, -2, "endsWith");
74 //              newFunction(t, &istartsWith, "istartsWith"); fielda(t, -2, "istartsWith");
75 //              newFunction(t, &iendsWith,   "iendsWith");   fielda(t, -2, "iendsWith");
76             setTypeMT(t, MDValue.Type.String);
77
78             return 0;
79         }, "string");
80        
81         fielda(t, -2, "string");
82         importModule(t, "string");
83         pop(t, 3);
84     }
85
86     uword join(MDThread* t, uword numParams)
87     {
88         checkParam(t, 1, MDValue.Type.Array);
89         checkStringParam(t, 2);
90         auto data = getArray(t, 1).slice;
91
92         if(data.length == 0)
93         {
94             pushString(t, "");
95             return 1;
96         }
97
98         auto buf = StrBuffer(t);
99        
100         idxi(t, 1, 0);
101        
102         if(!isString(t, -1))
103             throwException(t, "Array element 0 is not a string");
104            
105         buf.addTop();
106
107         foreach(i, ref val; data[1 .. $])
108         {
109             if(val.type != MDValue.Type.String)
110                 throwException(t, "Array element {} is not a string", i + 1);
111
112             dup(t, 2);
113             buf.addTop();
114             pushStringObj(t, val.mString);
115             buf.addTop();
116         }
117
118         buf.finish();
119         return 1;
120     }
121
122     uword toInt(MDThread* t, uword numParams)
123     {
124         auto src = checkStringParam(t, 0);
125
126         int base = 10;
127
128         if(numParams > 0)
129             base = cast(int)getInt(t, 1);
130
131         pushInt(t, safeCode(t, Integer.toInt(src, base)));
132         return 1;
133     }
134
135     uword toFloat(MDThread* t, uword numParams)
136     {
137         pushFloat(t, safeCode(t, Float.toFloat(checkStringParam(t, 0))));
138         return 1;
139     }
140
141     uword compare(MDThread* t, uword numParams)
142     {
143         pushInt(t, scmp(checkStringParam(t, 0), checkStringParam(t, 1)));
144         return 1;
145     }
146
147 //  uword icompare(MDThread* t, uword numParams)
148 //  {
149 //      pushInt(t, idcmp(checkStringParam(t, 0), checkStringParam(t, 1)));
150 //      return 1;
151 //  }
152
153     uword find(MDThread* t, uword numParams)
154     {
155         auto src = checkStringParam(t, 0);
156         auto srcLen = len(t, 0);
157         auto start = optIntParam(t, 2, 0);
158
159         if(start < 0)
160         {
161             start += srcLen;
162
163             if(start < 0)
164                 throwException(t, "Invalid start index {}", start);
165         }
166
167         if(start >= srcLen)
168         {
169             pushInt(t, srcLen);
170             return 1;
171         }
172
173         if(isString(t, 1))
174             pushInt(t, src.locatePattern(getString(t, 1), cast(uword)start));
175         else if(isChar(t, 1))
176         {
177             auto ch = getChar(t, 1);
178
179             uword startIdx = uniCPIdxToByte(src, cast(uword)start);
180
181             foreach(i, dchar c; src[startIdx .. $])
182             {
183                 if(c == ch)
184                 {
185                     pushInt(t, i + start);
186                     return 1;
187                 }
188             }
189
190             pushInt(t, src.length);
191         }
192         else
193         {
194             pushTypeString(t, 1);
195             throwException(t, "Parameter must be 'string' or 'char', not '{}'", getString(t, -1));
196         }
197
198         return 1;
199     }
200
201 //  uword ifind(MDThread* t, uword numParams)
202 //  {
203 //      dchar[32] buf1, buf2;
204 //      dchar[] src = Uni.toFold(s.getContext!(MDString).mData, buf1);
205 //      uword result;
206 //
207 //      if(s.isParam!("string")(0))
208 //          result = src.locatePattern(Uni.toFold(s.getParam!(MDString)(0).mData, buf2));
209 //      else if(s.isParam!("char")(0))
210 //          result = src.locate(Uni.toFold([s.getParam!(dchar)(0)], buf2)[0]);
211 //      else
212 //          s.throwRuntimeException("Second parameter must be string or int");
213 //
214 //      s.push(result);
215 //
216 //      return 1;
217 //  }
218
219     uword rfind(MDThread* t, uword numParams)
220     {
221         auto src = checkStringParam(t, 0);
222         auto srcLen = len(t, 0);
223         auto start = optIntParam(t, 2, srcLen);
224        
225         if(start > srcLen)
226             throwException(t, "Invalid start index: {}", start);
227
228         if(start < 0)
229         {
230             start += srcLen;
231
232             if(start < 0)
233                 throwException(t, "Invalid start index {}", start);
234         }
235
236         if(start == 0)
237         {
238             pushInt(t, srcLen);
239             return 1;
240         }
241
242         if(isString(t, 1))
243             pushInt(t, src.locatePatternPrior(getString(t, 1), cast(uword)start));
244         else if(isChar(t, 1))
245         {
246             auto ch = getChar(t, 1);
247             uword startIdx = uniCPIdxToByte(src, cast(uword)start);
248
249             foreach_reverse(i, dchar c; src[0 .. startIdx])
250             {
251                 if(c == ch)
252                 {
253                     pushInt(t, i);
254                     return 1;
255                 }
256             }
257
258             pushInt(t, src.length);
259         }
260         else
261         {
262             pushTypeString(t, 1);
263             throwException(t, "Parameter must be 'string' or 'char', not '{}'", getString(t, -1));
264         }
265
266         return 1;
267     }
268
269 //  uword irfind(MDThread* t, uword numParams)
270 //  {
271 //      dchar[32] buf1, buf2;
272 //      dchar[] src = Uni.toFold(s.getContext!(MDString).mData, buf1);
273 //      uword result;
274 //
275 //      if(s.isParam!("string")(0))
276 //          result = src.locatePatternPrior(Uni.toFold(s.getParam!(MDString)(0).mData, buf2));
277 //      else if(s.isParam!("char")(0))
278 //          result = src.locatePrior(Uni.toFold([s.getParam!(dchar)(0)], buf2)[0]);
279 //      else
280 //          s.throwRuntimeException("Second parameter must be string or int");
281 //
282 //      s.push(result);
283 //
284 //      return 1;
285 //  }
286
287     uword toLower(MDThread* t, uword numParams)
288     {
289         auto src = checkStringParam(t, 0);
290         auto buf = StrBuffer(t);
291        
292         foreach(dchar c; src)
293         {
294             dchar[4] outbuf = void;
295            
296             foreach(ch; Uni.toLower((&c)[0 .. 1], outbuf))
297                 buf.addChar(ch);
298         }
299
300         buf.finish();
301         return 1;
302     }
303
304     uword toUpper(MDThread* t, uword numParams)
305     {
306         auto src = checkStringParam(t, 0);
307         auto buf = StrBuffer(t);
308        
309         foreach(dchar c; src)
310         {
311             dchar[4] outbuf = void;
312            
313             foreach(ch; Uni.toUpper((&c)[0 .. 1], outbuf))
314                 buf.addChar(ch);
315         }
316
317         buf.finish();
318         return 1;
319     }
320
321     uword repeat(MDThread* t, uword numParams)
322     {
323         checkStringParam(t, 0);
324         auto numTimes = checkIntParam(t, 1);
325
326         if(numTimes < 0)
327             throwException(t, "Invalid number of repetitions: {}", numTimes);
328
329         auto buf = StrBuffer(t);
330
331         for(mdint i = 0; i < numTimes; i++)
332         {
333             dup(t, 0);
334             buf.addTop();
335         }
336
337         buf.finish();
338         return 1;
339     }
340
341     uword reverse(MDThread* t, uword numParams)
342     {
343         auto src = checkStringParam(t, 0);
344
345         if(src.length <= 1)
346             dup(t, 0);
347         else if(src.length <= 256)
348         {
349             char[256] buf = void;
350             auto s = buf[0 .. src.length];
351             s[] = src[];
352             s.reverse;
353             pushString(t, s);
354         }
355         else
356         {
357             auto tmp = t.vm.alloc.allocArray!(char)(src.length);
358             scope(exit) t.vm.alloc.freeArray(tmp);
359            
360             tmp[] = src[];
361             tmp.reverse;
362             pushString(t, tmp);
363         }
364
365         return 1;
366     }
367
368     uword split(MDThread* t, uword numParams)
369     {
370         auto src = checkStringParam(t, 0);
371         auto ret = newArray(t, 0);
372         uword num = 0;
373
374         if(numParams > 0)
375         {
376             foreach(piece; src.patterns(checkStringParam(t, 1)))
377             {
378                 pushString(t, piece);
379                 num++;
380                
381                 if(num >= 50)
382                 {
383                     cateq(t, ret, num);
384                     num = 0;
385                 }
386             }
387         }
388         else
389         {
390             foreach(piece; src.delimiters(" \t\v\r\n\f\u2028\u2029"))
391             {
392                 if(piece.length > 0)
393                 {
394                     pushString(t, piece);
395                     num++;
396
397                     if(num >= 50)
398                     {
399                         cateq(t, ret, num);
400                         num = 0;
401                     }
402                 }
403             }
404         }
405
406         if(num > 0)
407             cateq(t, ret, num);
408
409         return 1;
410     }
411
412     uword splitLines(MDThread* t, uword numParams)
413     {
414         auto src = checkStringParam(t, 0);
415         auto ret = newArray(t, 0);
416         uword num = 0;
417
418         foreach(line; src.lines())
419         {
420             pushString(t, line);
421             num++;
422            
423             if(num >= 50)
424             {
425                 cateq(t, ret, num);
426                 num = 0;
427             }
428         }
429
430         if(num > 0)
431             cateq(t, ret, num);
432
433         return 1;
434     }
435
436     uword strip(MDThread* t, uword numParams)
437     {
438         pushString(t, checkStringParam(t, 0).trim());
439         return 1;
440     }
441
442     uword lstrip(MDThread* t, uword numParams)
443     {
444         pushString(t, checkStringParam(t, 0).triml());
445         return 1;
446     }
447
448     uword rstrip(MDThread* t, uword numParams)
449     {
450         pushString(t, checkStringParam(t, 0).trimr());
451         return 1;
452     }
453
454     uword replace(MDThread* t, uword numParams)
455     {
456         auto src = checkStringParam(t, 0);
457         auto from = checkStringParam(t, 1);
458         auto to = checkStringParam(t, 2);
459         auto buf = StrBuffer(t);
460
461         foreach(piece; src.patterns(from, to))
462             buf.addString(piece);
463
464         buf.finish();
465         return 1;
466     }
467
468     uword iterator(MDThread* t, uword numParams)
469     {
470         checkParam(t, 0, MDValue.Type.String);
471         auto index = checkIntParam(t, 1) + 1;
472
473         if(index >= len(t, 0))
474             return 0;
475
476         pushInt(t, index);
477         dup(t);
478         idx(t, 0);
479
480         return 2;
481     }
482
483     uword iteratorReverse(MDThread* t, uword numParams)
484     {
485         checkParam(t, 0, MDValue.Type.String);
486         auto index = checkIntParam(t, 1) - 1;
487
488         if(index < 0)
489             return 0;
490
491         pushInt(t, index);
492         dup(t);
493         idx(t, 0);
494
495         return 2;
496     }
497
498     uword opApply(MDThread* t, uword numParams)
499     {
500         checkParam(t, 0, MDValue.Type.String);
501
502         if(optStringParam(t, 1, "") == "reverse")
503         {
504             getUpval(t, 1);
505             dup(t, 0);
506             pushLen(t, 0);
507         }
508         else
509         {
510             getUpval(t, 0);
511             dup(t, 0);
512             pushInt(t, -1);
513         }
514
515         return 3;
516     }
517
518     uword startsWith(MDThread* t, uword numParams)
519     {
520         pushBool(t, .startsWith(checkStringParam(t, 0), checkStringParam(t, 1)));
521         return 1;
522     }
523
524     uword endsWith(MDThread* t, uword numParams)
525     {
526         pushBool(t, .endsWith(checkStringParam(t, 0), checkStringParam(t, 1)));
527         return 1;
528     }
529
530 //  uword istartsWith(MDThread* t, uword numParams)
531 //  {
532 //      dchar[32] buf1, buf2;
533 //      auto string = Uni.toFold(s.getContext!(MDString).mData, buf1);
534 //      auto pattern = Uni.toFold(s.getParam!(MDString)(0).mData, buf2);
535 //
536 //      if(pattern.length > string.length)
537 //          s.push(false);
538 //      else
539 //          s.push(string[0 .. pattern.length] == pattern[]);
540 //
541 //      return 1;
542 //  }
543 //
544 //  uword iendsWith(MDThread* t, uword numParams)
545 //  {
546 //      dchar[32] buf1, buf2;
547 //      auto string = Uni.toFold(s.getContext!(MDString).mData, buf1);
548 //      auto pattern = Uni.toFold(s.getParam!(MDString)(0).mData, buf2);
549 //
550 //      if(pattern.length > string.length)
551 //          s.push(false);
552 //      else
553 //          s.push(string[$ - pattern.length .. $] == pattern[]);
554 //
555 //      return 1;
556 //  }
557 }
Note: See TracBrowser for help on using the browser.