Mercurial > projects > dmdscript-tango
comparison dmdscript_tango/dstring.d @ 0:55c2951c07be
initial, files origin, premoved tree
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 12:34:47 +0200 |
parents | |
children | 8363a4bf6a8f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:55c2951c07be |
---|---|
1 | |
2 /* Digital Mars DMDScript source code. | |
3 * Copyright (c) 2000-2002 by Chromium Communications | |
4 * D version Copyright (c) 2004-2006 by Digital Mars | |
5 * All Rights Reserved | |
6 * written by Walter Bright | |
7 * www.digitalmars.com | |
8 * Use at your own risk. There is no warranty, express or implied. | |
9 * License for redistribution is by the GNU General Public License in gpl.txt. | |
10 * | |
11 * A binary, non-exclusive license for commercial use can be | |
12 * purchased from www.digitalmars.com/dscript/buy.html. | |
13 * | |
14 * DMDScript is implemented in the D Programming Language, | |
15 * www.digitalmars.com/d/ | |
16 * | |
17 * For a C++ implementation of DMDScript, including COM support, | |
18 * see www.digitalmars.com/dscript/cppscript.html. | |
19 */ | |
20 | |
21 | |
22 module dmdscript.dstring; | |
23 | |
24 import std.regexp; | |
25 import std.utf; | |
26 import std.c.stdlib; | |
27 import std.c.string; | |
28 | |
29 import dmdscript.script; | |
30 import dmdscript.dobject; | |
31 import dmdscript.dregexp; | |
32 import dmdscript.darray; | |
33 import dmdscript.value; | |
34 import dmdscript.threadcontext; | |
35 import dmdscript.dfunction; | |
36 import dmdscript.text; | |
37 import dmdscript.property; | |
38 import dmdscript.errmsgs; | |
39 import dmdscript.dnative; | |
40 | |
41 //alias script.tchar tchar; | |
42 | |
43 /* ===================== Dstring_fromCharCode ==================== */ | |
44 | |
45 void* Dstring_fromCharCode(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
46 { | |
47 // ECMA 15.5.3.2 | |
48 d_string s; | |
49 | |
50 for (size_t i = 0; i < arglist.length; i++) | |
51 { Value* v; | |
52 uint u; | |
53 | |
54 v = &arglist[i]; | |
55 u = v.toUint16(); | |
56 //writefln("string.fromCharCode(%x)", u); | |
57 if (!std.utf.isValidDchar(u)) | |
58 { | |
59 ErrInfo errinfo; | |
60 | |
61 ret.putVundefined(); | |
62 return pthis.RuntimeError(&errinfo, | |
63 errmsgtbl[ERR_NOT_VALID_UTF], | |
64 "String", "fromCharCode()", | |
65 u); | |
66 } | |
67 std.utf.encode(s, u); | |
68 //writefln("s[0] = %x, s = '%s'", s[0], s); | |
69 } | |
70 ret.putVstring(s); | |
71 return null; | |
72 } | |
73 | |
74 /* ===================== Dstring_constructor ==================== */ | |
75 | |
76 class Dstring_constructor : Dfunction | |
77 { | |
78 this(ThreadContext *tc) | |
79 { | |
80 super(1, tc.Dfunction_prototype); | |
81 name = "String"; | |
82 | |
83 static NativeFunctionData nfd[] = | |
84 [ | |
85 { &TEXT_fromCharCode, &Dstring_fromCharCode, 1 }, | |
86 ]; | |
87 | |
88 DnativeFunction.init(this, nfd, 0); | |
89 } | |
90 | |
91 void *Construct(CallContext *cc, Value *ret, Value[] arglist) | |
92 { | |
93 // ECMA 15.5.2 | |
94 d_string s; | |
95 Dobject o; | |
96 | |
97 s = (arglist.length) ? arglist[0].toString() : TEXT_; | |
98 o = new Dstring(s); | |
99 ret.putVobject(o); | |
100 return null; | |
101 } | |
102 | |
103 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist) | |
104 { | |
105 // ECMA 15.5.1 | |
106 d_string s; | |
107 | |
108 s = (arglist.length) ? arglist[0].toString() : TEXT_; | |
109 ret.putVstring(s); | |
110 return null; | |
111 } | |
112 } | |
113 | |
114 | |
115 /* ===================== Dstring_prototype_toString =============== */ | |
116 | |
117 void* Dstring_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
118 { | |
119 //writef("Dstring.prototype.toString()\n"); | |
120 // othis must be a String | |
121 if (!othis.isClass(TEXT_String)) | |
122 { | |
123 ErrInfo errinfo; | |
124 | |
125 ret.putVundefined(); | |
126 return pthis.RuntimeError(&errinfo, | |
127 errmsgtbl[ERR_FUNCTION_WANTS_STRING], | |
128 TEXT_toString, | |
129 othis.classname); | |
130 } | |
131 else | |
132 { Value *v; | |
133 | |
134 v = &(cast(Dstring)othis).value; | |
135 Value.copy(ret, v); | |
136 } | |
137 return null; | |
138 } | |
139 | |
140 /* ===================== Dstring_prototype_valueOf =============== */ | |
141 | |
142 void* Dstring_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
143 { | |
144 // Does same thing as String.prototype.toString() | |
145 | |
146 //writef("string.prototype.valueOf()\n"); | |
147 // othis must be a String | |
148 if (!othis.isClass(TEXT_String)) | |
149 { | |
150 ErrInfo errinfo; | |
151 | |
152 ret.putVundefined(); | |
153 return pthis.RuntimeError(&errinfo, | |
154 errmsgtbl[ERR_FUNCTION_WANTS_STRING], | |
155 TEXT_valueOf, | |
156 othis.classname); | |
157 } | |
158 else | |
159 { Value *v; | |
160 | |
161 v = &(cast(Dstring)othis).value; | |
162 Value.copy(ret, v); | |
163 } | |
164 return null; | |
165 } | |
166 | |
167 /* ===================== Dstring_prototype_charAt =============== */ | |
168 | |
169 void* Dstring_prototype_charAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
170 { | |
171 // ECMA 15.5.4.4 | |
172 | |
173 Value *v; | |
174 int pos; // ECMA says pos should be a d_number, | |
175 // but int should behave the same | |
176 d_string s; | |
177 d_string result; | |
178 | |
179 v = &othis.value; | |
180 s = v.toString(); | |
181 v = arglist.length ? &arglist[0] : &vundefined; | |
182 pos = cast(int) v.toInteger(); | |
183 | |
184 result = TEXT_; | |
185 | |
186 if (pos >= 0) | |
187 { size_t idx; | |
188 | |
189 while (1) | |
190 { | |
191 if (idx == s.length) | |
192 break; | |
193 if (pos == 0) | |
194 { | |
195 result = s[idx .. idx + std.utf.stride(s, idx)]; | |
196 break; | |
197 } | |
198 idx += std.utf.stride(s, idx); | |
199 pos--; | |
200 } | |
201 } | |
202 | |
203 ret.putVstring(result); | |
204 return null; | |
205 } | |
206 | |
207 /* ===================== Dstring_prototype_charCodeAt ============= */ | |
208 | |
209 void* Dstring_prototype_charCodeAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
210 { | |
211 // ECMA 15.5.4.5 | |
212 | |
213 Value *v; | |
214 int pos; // ECMA says pos should be a d_number, | |
215 // but int should behave the same | |
216 d_string s; | |
217 uint len; | |
218 d_number result; | |
219 | |
220 v = &othis.value; | |
221 s = v.toString(); | |
222 v = arglist.length ? &arglist[0] : &vundefined; | |
223 pos = cast(int) v.toInteger(); | |
224 | |
225 result = d_number.nan; | |
226 | |
227 if (pos >= 0) | |
228 { size_t idx; | |
229 | |
230 while (1) | |
231 { | |
232 assert(idx <= s.length); | |
233 if (idx == s.length) | |
234 break; | |
235 if (pos == 0) | |
236 { | |
237 result = std.utf.decode(s, idx); | |
238 break; | |
239 } | |
240 idx += std.utf.stride(s, idx); | |
241 pos--; | |
242 } | |
243 } | |
244 | |
245 ret.putVnumber(result); | |
246 return null; | |
247 } | |
248 | |
249 /* ===================== Dstring_prototype_concat ============= */ | |
250 | |
251 void* Dstring_prototype_concat(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
252 { | |
253 // ECMA v3 15.5.4.6 | |
254 d_string s; | |
255 | |
256 //writefln("Dstring.prototype.concat()"); | |
257 | |
258 s = othis.value.toString(); | |
259 for (size_t a = 0; a < arglist.length; a++) | |
260 s ~= arglist[a].toString(); | |
261 | |
262 ret.putVstring(s); | |
263 return null; | |
264 } | |
265 | |
266 /* ===================== Dstring_prototype_indexOf ============= */ | |
267 | |
268 void* Dstring_prototype_indexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
269 { | |
270 // ECMA 15.5.4.6 | |
271 // String.prototype.indexOf(searchString, position) | |
272 | |
273 Value* v1; | |
274 Value* v2; | |
275 int pos; // ECMA says pos should be a d_number, | |
276 // but I can't find a reason. | |
277 d_string s; | |
278 size_t sUCSdim; | |
279 | |
280 d_string searchString; | |
281 int k; | |
282 | |
283 Value xx; | |
284 xx.putVobject(othis); | |
285 s = xx.toString(); | |
286 sUCSdim = std.utf.toUCSindex(s, s.length); | |
287 | |
288 v1 = arglist.length ? &arglist[0] : &vundefined; | |
289 v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined; | |
290 | |
291 searchString = v1.toString(); | |
292 pos = cast(int) v2.toInteger(); | |
293 | |
294 if (pos < 0) | |
295 pos = 0; | |
296 else if (pos > sUCSdim) | |
297 pos = sUCSdim; | |
298 | |
299 if (searchString.length == 0) | |
300 k = pos; | |
301 else | |
302 { pos = std.utf.toUTFindex(s, pos); | |
303 k = std.string.find(s[pos .. length], searchString); | |
304 if (k != -1) | |
305 k = std.utf.toUCSindex(s, pos + k); | |
306 } | |
307 | |
308 ret.putVnumber(k); | |
309 return null; | |
310 } | |
311 | |
312 /* ===================== Dstring_prototype_lastIndexOf ============= */ | |
313 | |
314 void* Dstring_prototype_lastIndexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
315 { | |
316 // ECMA v3 15.5.4.8 | |
317 // String.prototype.lastIndexOf(searchString, position) | |
318 | |
319 Value *v1; | |
320 int pos; // ECMA says pos should be a d_number, | |
321 // but I can't find a reason. | |
322 d_string s; | |
323 size_t sUCSdim; | |
324 d_string searchString; | |
325 int k; | |
326 | |
327 version (all) | |
328 { | |
329 { | |
330 // This is the 'transferable' version | |
331 Value *v; | |
332 void *a; | |
333 v = othis.Get(TEXT_toString); | |
334 a = v.Call(cc, othis, ret, null); | |
335 if (a) // if exception was thrown | |
336 return a; | |
337 s = ret.toString(); | |
338 } | |
339 } | |
340 else | |
341 { | |
342 // the 'builtin' version | |
343 s = othis.value.toString(); | |
344 } | |
345 sUCSdim = std.utf.toUCSindex(s, s.length); | |
346 | |
347 v1 = arglist.length ? &arglist[0] : &vundefined; | |
348 searchString = v1.toString(); | |
349 if (arglist.length >= 2) | |
350 { d_number n; | |
351 Value *v = &arglist[1]; | |
352 | |
353 n = v.toNumber(); | |
354 if (std.math.isnan(n) || n > sUCSdim) | |
355 pos = sUCSdim; | |
356 else if (n < 0) | |
357 pos = 0; | |
358 else | |
359 pos = cast(int) n; | |
360 } | |
361 else | |
362 pos = sUCSdim; | |
363 | |
364 //writef("len = %d, p = '%ls'\n", len, p); | |
365 //writef("pos = %d, sslen = %d, ssptr = '%ls'\n", pos, sslen, ssptr); | |
366 //writefln("s = '%s', pos = %s, searchString = '%s'", s, pos, searchString); | |
367 | |
368 if (searchString.length == 0) | |
369 k = pos; | |
370 else | |
371 { | |
372 pos = std.utf.toUTFindex(s, pos); | |
373 pos += searchString.length; | |
374 if (pos > s.length) | |
375 pos = s.length; | |
376 k = std.string.rfind(s[0 .. pos], searchString); | |
377 //writefln("s = '%s', pos = %s, searchString = '%s', k = %d", s, pos, searchString, k); | |
378 if (k != -1) | |
379 k = std.utf.toUCSindex(s, k); | |
380 } | |
381 ret.putVnumber(k); | |
382 return null; | |
383 } | |
384 | |
385 /* ===================== Dstring_prototype_localeCompare ============= */ | |
386 | |
387 void* Dstring_prototype_localeCompare(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
388 { | |
389 // ECMA v3 15.5.4.9 | |
390 d_string s1; | |
391 d_string s2; | |
392 d_number n; | |
393 Value *v; | |
394 | |
395 v = &othis.value; | |
396 s1 = v.toString(); | |
397 s2 = arglist.length ? arglist[0].toString() : vundefined.toString(); | |
398 n = localeCompare(cc, s1, s2); | |
399 ret.putVnumber(n); | |
400 return null; | |
401 } | |
402 | |
403 /* ===================== Dstring_prototype_match ============= */ | |
404 | |
405 void* Dstring_prototype_match(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
406 { | |
407 // ECMA v3 15.5.4.10 | |
408 Dregexp r; | |
409 Dobject o; | |
410 | |
411 if (arglist.length && !arglist[0].isPrimitive() && | |
412 (o = arglist[0].toObject()).isDregexp()) | |
413 { | |
414 ; | |
415 } | |
416 else | |
417 { | |
418 Value regret; | |
419 | |
420 regret.putVobject(null); | |
421 Dregexp.getConstructor().Construct(cc, ®ret, arglist); | |
422 o = regret.object; | |
423 } | |
424 | |
425 r = cast(Dregexp)o; | |
426 if (r.global.dbool) | |
427 { | |
428 Darray a = new Darray; | |
429 d_int32 n; | |
430 d_int32 i; | |
431 d_int32 lasti; | |
432 | |
433 i = 0; | |
434 lasti = 0; | |
435 for (n = 0; ; n++) | |
436 { | |
437 r.lastIndex.putVnumber(i); | |
438 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING); | |
439 if (!ret.string) // if match failed | |
440 { | |
441 r.lastIndex.putVnumber(i); | |
442 break; | |
443 } | |
444 lasti = i; | |
445 i = cast(d_int32) r.lastIndex.toInt32(); | |
446 if (i == lasti) // if no source was consumed | |
447 i++; // consume a character | |
448 | |
449 a.Put(n, ret, 0); // a[n] = ret; | |
450 } | |
451 ret.putVobject(a); | |
452 } | |
453 else | |
454 { | |
455 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_ARRAY); | |
456 } | |
457 return null; | |
458 } | |
459 | |
460 /* ===================== Dstring_prototype_replace ============= */ | |
461 | |
462 void* Dstring_prototype_replace(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
463 { | |
464 // ECMA v3 15.5.4.11 | |
465 // String.prototype.replace(searchValue, replaceValue) | |
466 | |
467 d_string string; | |
468 d_string searchString; | |
469 d_string newstring; | |
470 Value *searchValue; | |
471 Value *replaceValue; | |
472 Dregexp r; | |
473 RegExp re; | |
474 tchar[] replacement; | |
475 d_string result; | |
476 int m; | |
477 int i; | |
478 int lasti; | |
479 std.regexp.regmatch_t[1] pmatch; | |
480 Dfunction f; | |
481 Value* v; | |
482 | |
483 v = &othis.value; | |
484 string = v.toString(); | |
485 searchValue = (arglist.length >= 1) ? &arglist[0] : &vundefined; | |
486 replaceValue = (arglist.length >= 2) ? &arglist[1] : &vundefined; | |
487 r = Dregexp.isRegExp(searchValue); | |
488 f = Dfunction.isFunction(replaceValue); | |
489 if (r) | |
490 { int offset = 0; | |
491 | |
492 re = r.re; | |
493 i = 0; | |
494 result = string; | |
495 | |
496 r.lastIndex.putVnumber(0); | |
497 for (;;) | |
498 { | |
499 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING); | |
500 if (!ret.string) // if match failed | |
501 break; | |
502 | |
503 m = re.re_nsub; | |
504 if (f) | |
505 { | |
506 Value* alist; | |
507 | |
508 alist = cast(Value *)alloca((m + 3) * Value.sizeof); | |
509 assert(alist); | |
510 alist[0].putVstring(ret.string); | |
511 for (i = 0; i < m; i++) | |
512 { | |
513 alist[1 + i].putVstring( | |
514 string[re.pmatch[1 + i].rm_so .. re.pmatch[1 + i].rm_eo]); | |
515 } | |
516 alist[m + 1].putVnumber(re.pmatch[0].rm_so); | |
517 alist[m + 2].putVstring(string); | |
518 f.Call(cc, f, ret, alist[0 .. m + 3]); | |
519 replacement = ret.toString(); | |
520 } | |
521 else | |
522 { | |
523 newstring = replaceValue.toString(); | |
524 replacement = re.replace(newstring); | |
525 } | |
526 int starti = re.pmatch[0].rm_so + offset; | |
527 int endi = re.pmatch[0].rm_eo + offset; | |
528 result = string[0 .. starti] ~ | |
529 replacement ~ | |
530 string[endi .. length]; | |
531 | |
532 if (re.attributes & RegExp.REA.global) | |
533 { | |
534 offset += replacement.length - (endi - starti); | |
535 | |
536 // If no source was consumed, consume a character | |
537 lasti = i; | |
538 i = cast(d_int32) r.lastIndex.toInt32(); | |
539 if (i == lasti) | |
540 { i++; | |
541 r.lastIndex.putVnumber(i); | |
542 } | |
543 } | |
544 else | |
545 break; | |
546 } | |
547 } | |
548 else | |
549 { int match; | |
550 | |
551 searchString = searchValue.toString(); | |
552 match = std.string.find(string, searchString); | |
553 if (match >= 0) | |
554 { | |
555 pmatch[0].rm_so = match; | |
556 pmatch[0].rm_eo = match + searchString.length; | |
557 if (f) | |
558 { | |
559 Value[3] alist; | |
560 | |
561 alist[0].putVstring(searchString); | |
562 alist[1].putVnumber(pmatch[0].rm_so); | |
563 alist[2].putVstring(string); | |
564 f.Call(cc, f, ret, alist); | |
565 replacement = ret.toString(); | |
566 } | |
567 else | |
568 { | |
569 newstring = replaceValue.toString(); | |
570 replacement = RegExp.replace3(newstring, string, pmatch); | |
571 } | |
572 result = string[0 .. match] ~ | |
573 replacement ~ | |
574 string[match + searchString.length .. length]; | |
575 } | |
576 else | |
577 { | |
578 result = string; | |
579 } | |
580 } | |
581 | |
582 ret.putVstring(result); | |
583 return null; | |
584 } | |
585 | |
586 /* ===================== Dstring_prototype_search ============= */ | |
587 | |
588 void* Dstring_prototype_search(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
589 { | |
590 // ECMA v3 15.5.4.12 | |
591 Dregexp r; | |
592 Dobject o; | |
593 | |
594 //writef("String.prototype.search()\n"); | |
595 if (arglist.length && !arglist[0].isPrimitive() && | |
596 (o = arglist[0].toObject()).isDregexp()) | |
597 { | |
598 ; | |
599 } | |
600 else | |
601 { Value regret; | |
602 | |
603 regret.putVobject(null); | |
604 Dregexp.getConstructor().Construct(cc, ®ret, arglist); | |
605 o = regret.object; | |
606 } | |
607 | |
608 r = cast(Dregexp)o; | |
609 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_INDEX); | |
610 return null; | |
611 } | |
612 | |
613 /* ===================== Dstring_prototype_slice ============= */ | |
614 | |
615 void* Dstring_prototype_slice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
616 { | |
617 // ECMA v3 15.5.4.13 | |
618 d_int32 start; | |
619 d_int32 end; | |
620 d_int32 sUCSdim; | |
621 d_string s; | |
622 d_string r; | |
623 Value *v; | |
624 | |
625 v = &othis.value; | |
626 s = v.toString(); | |
627 sUCSdim = std.utf.toUCSindex(s, s.length); | |
628 switch (arglist.length) | |
629 { | |
630 case 0: | |
631 start = 0; | |
632 end = sUCSdim; | |
633 break; | |
634 | |
635 case 1: | |
636 start = arglist[0].toInt32(); | |
637 end = sUCSdim; | |
638 break; | |
639 | |
640 default: | |
641 start = arglist[0].toInt32(); | |
642 end = arglist[1].toInt32(); | |
643 break; | |
644 } | |
645 | |
646 if (start < 0) | |
647 { | |
648 start += sUCSdim; | |
649 if (start < 0) | |
650 start = 0; | |
651 } | |
652 else if (start >= sUCSdim) | |
653 start = sUCSdim; | |
654 | |
655 if (end < 0) | |
656 { | |
657 end += sUCSdim; | |
658 if (end < 0) | |
659 end = 0; | |
660 } | |
661 else if (end >= sUCSdim) | |
662 end = sUCSdim; | |
663 | |
664 if (start > end) | |
665 end = start; | |
666 | |
667 start = toUTFindex(s, start); | |
668 end = toUTFindex(s, end); | |
669 r = s[start .. end]; | |
670 | |
671 ret.putVstring(r); | |
672 return null; | |
673 } | |
674 | |
675 | |
676 /* ===================== Dstring_prototype_split ============= */ | |
677 | |
678 void* Dstring_prototype_split(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
679 { | |
680 // ECMA v3 15.5.4.14 | |
681 // String.prototype.split(separator, limit) | |
682 d_uint32 lim; | |
683 d_uint32 p; | |
684 d_uint32 q; | |
685 d_uint32 e; | |
686 Value* separator = &vundefined; | |
687 Value* limit = &vundefined; | |
688 Dregexp R; | |
689 RegExp re; | |
690 d_string rs; | |
691 d_string T; | |
692 d_string S; | |
693 Darray A; | |
694 int str; | |
695 | |
696 //writefln("Dstring_prototype_split()"); | |
697 switch (arglist.length) | |
698 { | |
699 default: | |
700 limit = &arglist[1]; | |
701 case 1: | |
702 separator = &arglist[0]; | |
703 case 0: | |
704 break; | |
705 } | |
706 | |
707 Value *v; | |
708 v = &othis.value; | |
709 S = v.toString(); | |
710 A = new Darray; | |
711 if (limit.isUndefined()) | |
712 lim = ~0u; | |
713 else | |
714 lim = limit.toUint32(); | |
715 p = 0; | |
716 R = Dregexp.isRegExp(separator); | |
717 if (R) // regular expression | |
718 { re = R.re; | |
719 assert(re); | |
720 rs = null; | |
721 str = 0; | |
722 } | |
723 else // string | |
724 { re = null; | |
725 rs = separator.toString(); | |
726 str = 1; | |
727 } | |
728 if (lim == 0) | |
729 goto Lret; | |
730 | |
731 // ECMA v3 15.5.4.14 is specific: "If separator is undefined, then the | |
732 // result array contains just one string, which is the this value | |
733 // (converted to a string)." However, neither Javascript nor Jscript | |
734 // do that, they regard an undefined as being the string "undefined". | |
735 // We match Javascript/Jscript behavior here, not ECMA. | |
736 | |
737 // Uncomment for ECMA compatibility | |
738 //if (!separator.isUndefined()) | |
739 { | |
740 //writefln("test1 S = '%s', rs = '%s'", S, rs); | |
741 if (S.length) | |
742 { | |
743 L10: | |
744 for (q = p; q != S.length; q++) | |
745 { | |
746 if (str) // string | |
747 { | |
748 if (q + rs.length <= S.length && !memcmp(S.ptr + q, rs.ptr, rs.length * tchar.sizeof)) | |
749 { | |
750 e = q + rs.length; | |
751 if (e != p) | |
752 { | |
753 T = S[p .. q]; | |
754 A.Put(cast(uint) A.length.number, T, 0); | |
755 if (A.length.number == lim) | |
756 goto Lret; | |
757 p = e; | |
758 goto L10; | |
759 } | |
760 } | |
761 } | |
762 else // regular expression | |
763 { | |
764 if (re.test(S, q)) | |
765 { q = re.pmatch[0].rm_so; | |
766 e = re.pmatch[0].rm_eo; | |
767 if (e != p) | |
768 { | |
769 T = S[p .. q]; | |
770 //writefln("S = '%s', T = '%s', p = %d, q = %d, e = %d\n", S, T, p, q, e); | |
771 A.Put(cast(uint) A.length.number, T, 0); | |
772 if (A.length.number == lim) | |
773 goto Lret; | |
774 p = e; | |
775 for (uint i = 0; i < re.re_nsub; i++) | |
776 { | |
777 int so = re.pmatch[1 + i].rm_so; | |
778 int eo = re.pmatch[1 + i].rm_eo; | |
779 | |
780 //writefln("i = %d, nsub = %s, so = %s, eo = %s, S.length = %s", i, re.re_nsub, so, eo, S.length); | |
781 if (so != -1 && eo != -1) | |
782 T = S[so .. eo]; | |
783 else | |
784 T = null; | |
785 A.Put(cast(uint) A.length.number, T, 0); | |
786 if (A.length.number == lim) | |
787 goto Lret; | |
788 } | |
789 goto L10; | |
790 } | |
791 } | |
792 } | |
793 } | |
794 T = S[p .. S.length]; | |
795 A.Put(cast(uint) A.length.number, T, 0); | |
796 goto Lret; | |
797 } | |
798 if (str) // string | |
799 { | |
800 if (rs.length <= S.length && S[0 .. rs.length] == rs[]) | |
801 goto Lret; | |
802 } | |
803 else // regular expression | |
804 { | |
805 if (re.test(S, 0)) | |
806 goto Lret; | |
807 } | |
808 } | |
809 | |
810 A.Put(0u, S, 0); | |
811 Lret: | |
812 ret.putVobject(A); | |
813 return null; | |
814 } | |
815 | |
816 | |
817 /* ===================== Dstring_prototype_substr ============= */ | |
818 | |
819 void *dstring_substring(d_string s, size_t sUCSdim, d_number start, d_number end, Value *ret) | |
820 { | |
821 d_string sb; | |
822 d_int32 sb_len; | |
823 | |
824 if (std.math.isnan(start)) | |
825 start = 0; | |
826 else if (start > sUCSdim) | |
827 start = sUCSdim; | |
828 else if (start < 0) | |
829 start = 0; | |
830 | |
831 if (std.math.isnan(end)) | |
832 end = 0; | |
833 else if (end > sUCSdim) | |
834 end = sUCSdim; | |
835 else if (end < 0) | |
836 end = 0; | |
837 | |
838 if (end < start) // swap | |
839 { d_number t; | |
840 | |
841 t = start; | |
842 start = end; | |
843 end = t; | |
844 } | |
845 | |
846 size_t st = std.utf.toUTFindex(s, cast(size_t)start); | |
847 size_t en = std.utf.toUTFindex(s, cast(size_t)end); | |
848 sb = s[st .. en]; | |
849 | |
850 ret.putVstring(sb); | |
851 return null; | |
852 } | |
853 | |
854 void* Dstring_prototype_substr(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
855 { | |
856 // Javascript: TDG pg. 689 | |
857 // String.prototype.substr(start, length) | |
858 d_number start; | |
859 d_number length; | |
860 d_string s; | |
861 | |
862 s = othis.value.toString(); | |
863 size_t sUCSdim = std.utf.toUCSindex(s, s.length); | |
864 start = 0; | |
865 length = 0; | |
866 if (arglist.length >= 1) | |
867 { | |
868 start = arglist[0].toInteger(); | |
869 if (start < 0) | |
870 start = sUCSdim + start; | |
871 if (arglist.length >= 2) | |
872 { | |
873 length = arglist[1].toInteger(); | |
874 if (std.math.isnan(length) || length < 0) | |
875 length = 0; | |
876 } | |
877 else | |
878 length = sUCSdim - start; | |
879 } | |
880 | |
881 return dstring_substring(s, sUCSdim, start, start + length, ret); | |
882 } | |
883 | |
884 /* ===================== Dstring_prototype_substring ============= */ | |
885 | |
886 void* Dstring_prototype_substring(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
887 { | |
888 // ECMA 15.5.4.9 | |
889 // String.prototype.substring(start) | |
890 // String.prototype.substring(start, end) | |
891 d_number start; | |
892 d_number end; | |
893 d_string s; | |
894 | |
895 //writefln("String.prototype.substring()"); | |
896 s = othis.value.toString(); | |
897 size_t sUCSdim = std.utf.toUCSindex(s, s.length); | |
898 start = 0; | |
899 end = sUCSdim; | |
900 if (arglist.length >= 1) | |
901 { | |
902 start = arglist[0].toInteger(); | |
903 if (arglist.length >= 2) | |
904 end = arglist[1].toInteger(); | |
905 //writef("s = '%ls', start = %d, end = %d\n", s, start, end); | |
906 } | |
907 | |
908 void* p = dstring_substring(s, sUCSdim, start, end, ret); | |
909 return p; | |
910 } | |
911 | |
912 /* ===================== Dstring_prototype_toLowerCase ============= */ | |
913 | |
914 enum CASE | |
915 { | |
916 Lower, | |
917 Upper, | |
918 LocaleLower, | |
919 LocaleUpper | |
920 }; | |
921 | |
922 void *tocase(Dobject othis, Value *ret, CASE caseflag) | |
923 { | |
924 d_string s; | |
925 | |
926 s = othis.value.toString(); | |
927 switch (caseflag) | |
928 { | |
929 case CASE.Lower: | |
930 s = std.string.tolower(s); | |
931 break; | |
932 case CASE.Upper: | |
933 s = std.string.toupper(s); | |
934 break; | |
935 case CASE.LocaleLower: | |
936 s = std.string.tolower(s); | |
937 break; | |
938 case CASE.LocaleUpper: | |
939 s = std.string.toupper(s); | |
940 break; | |
941 default: | |
942 assert(0); | |
943 } | |
944 | |
945 ret.putVstring(s); | |
946 return null; | |
947 } | |
948 | |
949 void* Dstring_prototype_toLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
950 { | |
951 // ECMA 15.5.4.11 | |
952 // String.prototype.toLowerCase() | |
953 | |
954 //writef("Dstring_prototype_toLowerCase()\n"); | |
955 return tocase(othis, ret, CASE.Lower); | |
956 } | |
957 | |
958 /* ===================== Dstring_prototype_toLocaleLowerCase ============= */ | |
959 | |
960 void* Dstring_prototype_toLocaleLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
961 { | |
962 // ECMA v3 15.5.4.17 | |
963 | |
964 //writef("Dstring_prototype_toLocaleLowerCase()\n"); | |
965 return tocase(othis, ret, CASE.LocaleLower); | |
966 } | |
967 | |
968 /* ===================== Dstring_prototype_toUpperCase ============= */ | |
969 | |
970 void* Dstring_prototype_toUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
971 { | |
972 // ECMA 15.5.4.12 | |
973 // String.prototype.toUpperCase() | |
974 | |
975 return tocase(othis, ret, CASE.Upper); | |
976 } | |
977 | |
978 /* ===================== Dstring_prototype_toLocaleUpperCase ============= */ | |
979 | |
980 void* Dstring_prototype_toLocaleUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
981 { | |
982 // ECMA v3 15.5.4.18 | |
983 | |
984 return tocase(othis, ret, CASE.LocaleUpper); | |
985 } | |
986 | |
987 /* ===================== Dstring_prototype_anchor ============= */ | |
988 | |
989 void *dstring_anchor(Dobject othis, Value* ret, tchar[] tag, tchar[] name, Value[] arglist) | |
990 { | |
991 // For example: | |
992 // "foo".anchor("bar") | |
993 // produces: | |
994 // <tag name="bar">foo</tag> | |
995 | |
996 d_string foo = othis.value.toString(); | |
997 Value* va = arglist.length ? &arglist[0] : &vundefined; | |
998 d_string bar = va.toString(); | |
999 | |
1000 d_string s; | |
1001 | |
1002 s = "<" ~ | |
1003 tag ~ | |
1004 " " ~ | |
1005 name ~ | |
1006 "=\"" ~ | |
1007 bar ~ | |
1008 "\">" ~ | |
1009 foo ~ | |
1010 "</" ~ | |
1011 tag ~ | |
1012 ">"; | |
1013 | |
1014 ret.putVstring(s); | |
1015 return null; | |
1016 } | |
1017 | |
1018 | |
1019 void* Dstring_prototype_anchor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1020 { | |
1021 // Non-standard extension | |
1022 // String.prototype.anchor(anchor) | |
1023 // For example: | |
1024 // "foo".anchor("bar") | |
1025 // produces: | |
1026 // <A NAME="bar">foo</A> | |
1027 | |
1028 return dstring_anchor(othis, ret, "A", "NAME", arglist); | |
1029 } | |
1030 | |
1031 void* Dstring_prototype_fontcolor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1032 { | |
1033 return dstring_anchor(othis, ret, "FONT", "COLOR", arglist); | |
1034 } | |
1035 | |
1036 void* Dstring_prototype_fontsize(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1037 { | |
1038 return dstring_anchor(othis, ret, "FONT", "SIZE", arglist); | |
1039 } | |
1040 | |
1041 void* Dstring_prototype_link(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1042 { | |
1043 return dstring_anchor(othis, ret, "A", "HREF", arglist); | |
1044 } | |
1045 | |
1046 | |
1047 /* ===================== Dstring_prototype bracketing ============= */ | |
1048 | |
1049 /*************************** | |
1050 * Produce <tag>othis</tag> | |
1051 */ | |
1052 | |
1053 void *dstring_bracket(Dobject othis, Value* ret, char[] tag) | |
1054 { | |
1055 d_string foo = othis.value.toString(); | |
1056 d_string s; | |
1057 | |
1058 s = "<" ~ | |
1059 tag ~ | |
1060 ">" ~ | |
1061 foo ~ | |
1062 "</" ~ | |
1063 tag ~ | |
1064 ">"; | |
1065 | |
1066 ret.putVstring(s); | |
1067 return null; | |
1068 } | |
1069 | |
1070 void* Dstring_prototype_big(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1071 { | |
1072 // Non-standard extension | |
1073 // String.prototype.big() | |
1074 // For example: | |
1075 // "foo".big() | |
1076 // produces: | |
1077 // <BIG>foo</BIG> | |
1078 | |
1079 return dstring_bracket(othis, ret, "BIG"); | |
1080 } | |
1081 | |
1082 void* Dstring_prototype_blink(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1083 { | |
1084 return dstring_bracket(othis, ret, "BLINK"); | |
1085 } | |
1086 | |
1087 void* Dstring_prototype_bold(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1088 { | |
1089 return dstring_bracket(othis, ret, "B"); | |
1090 } | |
1091 | |
1092 void* Dstring_prototype_fixed(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1093 { | |
1094 return dstring_bracket(othis, ret, "TT"); | |
1095 } | |
1096 | |
1097 void* Dstring_prototype_italics(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1098 { | |
1099 return dstring_bracket(othis, ret, "I"); | |
1100 } | |
1101 | |
1102 void* Dstring_prototype_small(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1103 { | |
1104 return dstring_bracket(othis, ret, "SMALL"); | |
1105 } | |
1106 | |
1107 void* Dstring_prototype_strike(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1108 { | |
1109 return dstring_bracket(othis, ret, "STRIKE"); | |
1110 } | |
1111 | |
1112 void* Dstring_prototype_sub(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1113 { | |
1114 return dstring_bracket(othis, ret, "SUB"); | |
1115 } | |
1116 | |
1117 void* Dstring_prototype_sup(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) | |
1118 { | |
1119 return dstring_bracket(othis, ret, "SUP"); | |
1120 } | |
1121 | |
1122 | |
1123 | |
1124 /* ===================== Dstring_prototype ==================== */ | |
1125 | |
1126 class Dstring_prototype : Dstring | |
1127 { | |
1128 this(ThreadContext *tc) | |
1129 { | |
1130 super(tc.Dobject_prototype); | |
1131 | |
1132 Put(TEXT_constructor, tc.Dstring_constructor, DontEnum); | |
1133 | |
1134 static NativeFunctionData nfd[] = | |
1135 [ | |
1136 { &TEXT_toString, &Dstring_prototype_toString, 0 }, | |
1137 { &TEXT_valueOf, &Dstring_prototype_valueOf, 0 }, | |
1138 { &TEXT_charAt, &Dstring_prototype_charAt, 1 }, | |
1139 { &TEXT_charCodeAt, &Dstring_prototype_charCodeAt, 1 }, | |
1140 { &TEXT_concat, &Dstring_prototype_concat, 1 }, | |
1141 { &TEXT_indexOf, &Dstring_prototype_indexOf, 1 }, | |
1142 { &TEXT_lastIndexOf, &Dstring_prototype_lastIndexOf, 1 }, | |
1143 { &TEXT_localeCompare, &Dstring_prototype_localeCompare, 1 }, | |
1144 { &TEXT_match, &Dstring_prototype_match, 1 }, | |
1145 { &TEXT_replace, &Dstring_prototype_replace, 2 }, | |
1146 { &TEXT_search, &Dstring_prototype_search, 1 }, | |
1147 { &TEXT_slice, &Dstring_prototype_slice, 2 }, | |
1148 { &TEXT_split, &Dstring_prototype_split, 2 }, | |
1149 { &TEXT_substr, &Dstring_prototype_substr, 2 }, | |
1150 { &TEXT_substring, &Dstring_prototype_substring, 2 }, | |
1151 { &TEXT_toLowerCase, &Dstring_prototype_toLowerCase, 0 }, | |
1152 { &TEXT_toLocaleLowerCase, &Dstring_prototype_toLocaleLowerCase, 0 }, | |
1153 { &TEXT_toUpperCase, &Dstring_prototype_toUpperCase, 0 }, | |
1154 { &TEXT_toLocaleUpperCase, &Dstring_prototype_toLocaleUpperCase, 0 }, | |
1155 { &TEXT_anchor, &Dstring_prototype_anchor, 1 }, | |
1156 { &TEXT_fontcolor, &Dstring_prototype_fontcolor, 1 }, | |
1157 { &TEXT_fontsize, &Dstring_prototype_fontsize, 1 }, | |
1158 { &TEXT_link, &Dstring_prototype_link, 1 }, | |
1159 { &TEXT_big, &Dstring_prototype_big, 0 }, | |
1160 { &TEXT_blink, &Dstring_prototype_blink, 0 }, | |
1161 { &TEXT_bold, &Dstring_prototype_bold, 0 }, | |
1162 { &TEXT_fixed, &Dstring_prototype_fixed, 0 }, | |
1163 { &TEXT_italics, &Dstring_prototype_italics, 0 }, | |
1164 { &TEXT_small, &Dstring_prototype_small, 0 }, | |
1165 { &TEXT_strike, &Dstring_prototype_strike, 0 }, | |
1166 { &TEXT_sub, &Dstring_prototype_sub, 0 }, | |
1167 { &TEXT_sup, &Dstring_prototype_sup, 0 }, | |
1168 ]; | |
1169 | |
1170 DnativeFunction.init(this, nfd, DontEnum); | |
1171 } | |
1172 } | |
1173 | |
1174 /* ===================== Dstring ==================== */ | |
1175 | |
1176 class Dstring : Dobject | |
1177 { | |
1178 this(d_string s) | |
1179 { | |
1180 super(getPrototype()); | |
1181 classname = TEXT_String; | |
1182 | |
1183 Put(TEXT_length, std.utf.toUCSindex(s, s.length), DontEnum | DontDelete | ReadOnly); | |
1184 value.putVstring(s); | |
1185 } | |
1186 | |
1187 this(Dobject prototype) | |
1188 { | |
1189 super(prototype); | |
1190 | |
1191 classname = TEXT_String; | |
1192 Put(TEXT_length, 0, DontEnum | DontDelete | ReadOnly); | |
1193 value.putVstring(null); | |
1194 } | |
1195 | |
1196 static void init(ThreadContext *tc) | |
1197 { | |
1198 tc.Dstring_constructor = new Dstring_constructor(tc); | |
1199 tc.Dstring_prototype = new Dstring_prototype(tc); | |
1200 | |
1201 tc.Dstring_constructor.Put(TEXT_prototype, tc.Dstring_prototype, DontEnum | DontDelete | ReadOnly); | |
1202 } | |
1203 | |
1204 static Dfunction getConstructor() | |
1205 { | |
1206 ThreadContext *tc = ThreadContext.getThreadContext(); | |
1207 assert(tc); | |
1208 return tc.Dstring_constructor; | |
1209 } | |
1210 | |
1211 static Dobject getPrototype() | |
1212 { | |
1213 ThreadContext *tc = ThreadContext.getThreadContext(); | |
1214 assert(tc); | |
1215 return tc.Dstring_prototype; | |
1216 } | |
1217 } |