0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2005 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.dregexp;
|
|
23
|
|
24 private import std.regexp;
|
|
25
|
|
26 import dmdscript.script;
|
|
27 import dmdscript.dobject;
|
|
28 import dmdscript.value;
|
|
29 import dmdscript.protoerror;
|
|
30 import dmdscript.text;
|
|
31 import dmdscript.darray;
|
|
32 import dmdscript.threadcontext;
|
|
33 import dmdscript.dfunction;
|
|
34 import dmdscript.property;
|
|
35 import dmdscript.errmsgs;
|
|
36 import dmdscript.dnative;
|
|
37
|
|
38 //alias script.tchar tchar;
|
|
39
|
|
40 // Values for Dregexp.exec.rettype
|
|
41 enum { EXEC_STRING, EXEC_ARRAY, EXEC_BOOLEAN, EXEC_INDEX };
|
|
42
|
|
43
|
|
44 /* ===================== Dregexp_constructor ==================== */
|
|
45
|
|
46 class Dregexp_constructor : Dfunction
|
|
47 {
|
|
48 Value* input;
|
|
49 Value* multiline;
|
|
50 Value* lastMatch;
|
|
51 Value* lastParen;
|
|
52 Value* leftContext;
|
|
53 Value* rightContext;
|
|
54 Value* dollar[10];
|
|
55
|
|
56 // Extensions
|
|
57 Value* index;
|
|
58 Value* lastIndex;
|
|
59
|
|
60 this(ThreadContext *tc)
|
|
61 {
|
|
62 super(2, tc.Dfunction_prototype);
|
|
63
|
|
64 Value v;
|
|
65 v.putVstring(null);
|
|
66
|
|
67 Value vb;
|
|
68 vb.putVboolean(false);
|
|
69
|
|
70 Value vnm1;
|
|
71 vnm1.putVnumber(-1);
|
|
72
|
|
73 name = "RegExp";
|
|
74
|
|
75 // Static properties
|
|
76 Put(TEXT_input, &v, DontDelete);
|
|
77 Put(TEXT_multiline, &vb, DontDelete);
|
|
78 Put(TEXT_lastMatch, &v, ReadOnly | DontDelete);
|
|
79 Put(TEXT_lastParen, &v, ReadOnly | DontDelete);
|
|
80 Put(TEXT_leftContext, &v, ReadOnly | DontDelete);
|
|
81 Put(TEXT_rightContext, &v, ReadOnly | DontDelete);
|
|
82 Put(TEXT_dollar1, &v, ReadOnly | DontDelete);
|
|
83 Put(TEXT_dollar2, &v, ReadOnly | DontDelete);
|
|
84 Put(TEXT_dollar3, &v, ReadOnly | DontDelete);
|
|
85 Put(TEXT_dollar4, &v, ReadOnly | DontDelete);
|
|
86 Put(TEXT_dollar5, &v, ReadOnly | DontDelete);
|
|
87 Put(TEXT_dollar6, &v, ReadOnly | DontDelete);
|
|
88 Put(TEXT_dollar7, &v, ReadOnly | DontDelete);
|
|
89 Put(TEXT_dollar8, &v, ReadOnly | DontDelete);
|
|
90 Put(TEXT_dollar9, &v, ReadOnly | DontDelete);
|
|
91
|
|
92 Put(TEXT_index, &vnm1, ReadOnly | DontDelete);
|
|
93 Put(TEXT_lastIndex, &vnm1, ReadOnly | DontDelete);
|
|
94
|
|
95 input = Get(TEXT_input);
|
|
96 multiline = Get(TEXT_multiline);
|
|
97 lastMatch = Get(TEXT_lastMatch);
|
|
98 lastParen = Get(TEXT_lastParen);
|
|
99 leftContext = Get(TEXT_leftContext);
|
|
100 rightContext = Get(TEXT_rightContext);
|
|
101 dollar[0] = lastMatch;
|
|
102 dollar[1] = Get(TEXT_dollar1);
|
|
103 dollar[2] = Get(TEXT_dollar2);
|
|
104 dollar[3] = Get(TEXT_dollar3);
|
|
105 dollar[4] = Get(TEXT_dollar4);
|
|
106 dollar[5] = Get(TEXT_dollar5);
|
|
107 dollar[6] = Get(TEXT_dollar6);
|
|
108 dollar[7] = Get(TEXT_dollar7);
|
|
109 dollar[8] = Get(TEXT_dollar8);
|
|
110 dollar[9] = Get(TEXT_dollar9);
|
|
111
|
|
112 index = Get(TEXT_index);
|
|
113 lastIndex = Get(TEXT_lastIndex);
|
|
114
|
|
115 // Should lastMatch be an alias for dollar[nparens],
|
|
116 // or should it be a separate property?
|
|
117 // We implemented it the latter way.
|
|
118 // Since both are ReadOnly, I can't see that it makes
|
|
119 // any difference.
|
|
120 }
|
|
121
|
|
122 void* Construct(CallContext *cc, Value *ret, Value[] arglist)
|
|
123 {
|
|
124 // ECMA 262 v3 15.10.4.1
|
|
125
|
|
126 Value* pattern;
|
|
127 Value* flags;
|
|
128 d_string P;
|
|
129 d_string F;
|
|
130 Dregexp r;
|
|
131 Dregexp R;
|
|
132
|
|
133 //writef("Dregexp_constructor.Construct()\n");
|
|
134 ret.putVundefined();
|
|
135 pattern = &vundefined;
|
|
136 flags = &vundefined;
|
|
137 switch (arglist.length)
|
|
138 {
|
|
139 case 0:
|
|
140 break;
|
|
141
|
|
142 default:
|
|
143 flags = &arglist[1];
|
|
144 case 1:
|
|
145 pattern = &arglist[0];
|
|
146 break;
|
|
147 }
|
|
148 R = Dregexp.isRegExp(pattern);
|
|
149 if (R)
|
|
150 {
|
|
151 if (flags.isUndefined())
|
|
152 {
|
|
153 P = R.re.pattern;
|
|
154 F = R.re.flags;
|
|
155 }
|
|
156 else
|
|
157 {
|
|
158 ErrInfo errinfo;
|
|
159 return RuntimeError(&errinfo, ERR_TYPE_ERROR,
|
|
160 "RegExp.prototype.constructor");
|
|
161 }
|
|
162 }
|
|
163 else
|
|
164 {
|
|
165 P = pattern.isUndefined() ? "" : pattern.toString();
|
|
166 F = flags.isUndefined() ? "" : flags.toString();
|
|
167 }
|
|
168 r = new Dregexp(P, F);
|
|
169 if (r.re.errors)
|
|
170 { Dobject o;
|
|
171 ErrInfo errinfo;
|
|
172
|
|
173 version (none)
|
|
174 {
|
|
175 writef("P = '%s'\nF = '%s'\n", d_string_ptr(P), d_string_ptr(F));
|
|
176 for (int i = 0; i < d_string_len(P); i++)
|
|
177 writef("x%02x\n", d_string_ptr(P)[i]);
|
|
178 }
|
|
179 errinfo.message = errmsgtbl[ERR_REGEXP_COMPILE];
|
|
180 o = new syntaxerror.D0(&errinfo);
|
|
181 Value* v = new Value;
|
|
182 v.putVobject(o);
|
|
183 return v;
|
|
184 }
|
|
185 else
|
|
186 {
|
|
187 ret.putVobject(r);
|
|
188 return null;
|
|
189 }
|
|
190 }
|
|
191
|
|
192 void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
|
|
193 {
|
|
194 // ECMA 262 v3 15.10.3.1
|
|
195 if (arglist.length >= 1)
|
|
196 { Value* pattern;
|
|
197 Dobject o;
|
|
198
|
|
199 pattern = &arglist[0];
|
|
200 if (!pattern.isPrimitive())
|
|
201 {
|
|
202 o = pattern.object;
|
|
203 if (o.isDregexp() &&
|
|
204 (arglist.length == 1 || arglist[1].isUndefined())
|
|
205 )
|
|
206 { ret.putVobject(o);
|
|
207 return null;
|
|
208 }
|
|
209 }
|
|
210 }
|
|
211 return Construct(cc, ret, arglist);
|
|
212 }
|
|
213
|
|
214
|
|
215 Value* Get(d_string PropertyName)
|
|
216 {
|
|
217 return Dfunction.Get(perlAlias(PropertyName));
|
|
218 }
|
|
219
|
|
220 Value* Put(d_string PropertyName, Value* value, uint attributes)
|
|
221 {
|
|
222 return Dfunction.Put(perlAlias(PropertyName), value, attributes);
|
|
223 }
|
|
224
|
|
225 Value* Put(d_string PropertyName, Dobject o, uint attributes)
|
|
226 {
|
|
227 return Dfunction.Put(perlAlias(PropertyName), o, attributes);
|
|
228 }
|
|
229
|
|
230 Value* Put(d_string PropertyName, d_number n, uint attributes)
|
|
231 {
|
|
232 return Dfunction.Put(perlAlias(PropertyName), n, attributes);
|
|
233 }
|
|
234
|
|
235 int CanPut(d_string PropertyName)
|
|
236 {
|
|
237 return Dfunction.CanPut(perlAlias(PropertyName));
|
|
238 }
|
|
239
|
|
240 int HasProperty(d_string PropertyName)
|
|
241 {
|
|
242 return Dfunction.HasProperty(perlAlias(PropertyName));
|
|
243 }
|
|
244
|
|
245 int Delete(d_string PropertyName)
|
|
246 {
|
|
247 return Dfunction.Delete(perlAlias(PropertyName));
|
|
248 }
|
|
249
|
|
250 // Translate Perl property names to script property names
|
|
251 static d_string perlAlias(d_string s)
|
|
252 {
|
|
253 d_string t;
|
|
254
|
|
255 static tchar[6] from = "_*&+`'";
|
|
256 static d_string*[] to =
|
|
257 [
|
|
258 &TEXT_input,
|
|
259 &TEXT_multiline,
|
|
260 &TEXT_lastMatch,
|
|
261 &TEXT_lastParen,
|
|
262 &TEXT_leftContext,
|
|
263 &TEXT_rightContext,
|
|
264 ];
|
|
265
|
|
266 t = s;
|
|
267 if (s.length == 2 && s[0] == '$')
|
|
268 { int i;
|
|
269
|
|
270 i = std.string.find(from, s[1]);
|
|
271 if (i >= 0)
|
|
272 t = *to[i];
|
|
273 }
|
|
274 return t;
|
|
275 }
|
|
276 }
|
|
277
|
|
278
|
|
279 /* ===================== Dregexp_prototype_toString =============== */
|
|
280
|
|
281 void* Dregexp_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
282 {
|
|
283 // othis must be a RegExp
|
|
284 Dregexp r;
|
|
285
|
|
286 if (!othis.isDregexp())
|
|
287 {
|
|
288 ret.putVundefined();
|
|
289 ErrInfo errinfo;
|
|
290 return Dobject.RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
|
|
291 "RegExp.prototype.toString()");
|
|
292 }
|
|
293 else
|
|
294 {
|
|
295 d_string s;
|
|
296
|
|
297 r = cast(Dregexp)(othis);
|
|
298 s = "/";
|
|
299 s ~= r.re.pattern;
|
|
300 s ~= "/";
|
|
301 s ~= r.re.flags;
|
|
302 ret.putVstring(s);
|
|
303 }
|
|
304 return null;
|
|
305 }
|
|
306
|
|
307 /* ===================== Dregexp_prototype_test =============== */
|
|
308
|
|
309 void* Dregexp_prototype_test(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
310 {
|
|
311 // ECMA v3 15.10.6.3 says this is equivalent to:
|
|
312 // RegExp.prototype.exec(string) != null
|
|
313 return Dregexp.exec(othis, ret, arglist, EXEC_BOOLEAN);
|
|
314 }
|
|
315
|
|
316 /* ===================== Dregexp_prototype_exec ============= */
|
|
317
|
|
318 void* Dregexp_prototype_exec(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
319 {
|
|
320 return Dregexp.exec(othis, ret, arglist, EXEC_ARRAY);
|
|
321 }
|
|
322
|
|
323
|
|
324 /* ===================== Dregexp_prototype_compile ============= */
|
|
325
|
|
326 void* Dregexp_prototype_compile(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
327 {
|
|
328 // RegExp.prototype.compile(pattern, attributes)
|
|
329
|
|
330 // othis must be a RegExp
|
|
331 if (!othis.isClass(TEXT_RegExp))
|
|
332 {
|
|
333 ErrInfo errinfo;
|
|
334 ret.putVundefined();
|
|
335 return Dobject.RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
|
|
336 "RegExp.prototype.compile()");
|
|
337 }
|
|
338 else
|
|
339 {
|
|
340 d_string pattern;
|
|
341 d_string attributes;
|
|
342 Dregexp dr;
|
|
343 RegExp r;
|
|
344
|
|
345 dr = cast(Dregexp)othis;
|
|
346 switch (arglist.length)
|
|
347 {
|
|
348 case 0:
|
|
349 break;
|
|
350
|
|
351 default:
|
|
352 attributes = arglist[1].toString();
|
|
353 case 1:
|
|
354 pattern = arglist[0].toString();
|
|
355 break;
|
|
356 }
|
|
357
|
|
358 r = dr.re;
|
|
359 try
|
|
360 {
|
|
361 r.compile(pattern, attributes);
|
|
362 }
|
|
363 catch (RegExpException e)
|
|
364 {
|
|
365 // Affect source, global and ignoreCase properties
|
|
366 dr.source.putVstring(r.pattern);
|
|
367 dr.global.putVboolean((r.attributes & RegExp.REA.global) != 0);
|
|
368 dr.ignoreCase.putVboolean((r.attributes & RegExp.REA.ignoreCase) != 0);
|
|
369 }
|
|
370 //writef("r.attributes = x%x\n", r.attributes);
|
|
371 }
|
|
372 // Documentation says nothing about a return value,
|
|
373 // so let's use "undefined"
|
|
374 ret.putVundefined();
|
|
375 return null;
|
|
376 }
|
|
377
|
|
378 /* ===================== Dregexp_prototype ==================== */
|
|
379
|
|
380 class Dregexp_prototype : Dregexp
|
|
381 {
|
|
382 this(ThreadContext *tc)
|
|
383 {
|
|
384 super(tc.Dobject_prototype);
|
|
385 classname = TEXT_Object;
|
|
386 uint attributes = ReadOnly | DontDelete | DontEnum;
|
|
387 Dobject f = tc.Dfunction_prototype;
|
|
388
|
|
389 Put(TEXT_constructor, tc.Dregexp_constructor, attributes);
|
|
390
|
|
391 static NativeFunctionData nfd[] =
|
|
392 [
|
|
393 { &TEXT_toString, &Dregexp_prototype_toString, 0 },
|
|
394 { &TEXT_compile, &Dregexp_prototype_compile, 2 },
|
|
395 { &TEXT_exec, &Dregexp_prototype_exec, 1 },
|
|
396 { &TEXT_test, &Dregexp_prototype_test, 1 },
|
|
397 ];
|
|
398
|
|
399 DnativeFunction.init(this, nfd, attributes);
|
|
400 }
|
|
401 }
|
|
402
|
|
403
|
|
404 /* ===================== Dregexp ==================== */
|
|
405
|
|
406
|
|
407 class Dregexp : Dobject
|
|
408 {
|
|
409 Value *global;
|
|
410 Value *ignoreCase;
|
|
411 Value *multiline;
|
|
412 Value *lastIndex;
|
|
413 Value *source;
|
|
414
|
|
415 RegExp re;
|
|
416
|
|
417 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist);
|
|
418
|
|
419 this(d_string pattern, d_string attributes)
|
|
420 {
|
|
421 super(getPrototype());
|
|
422
|
|
423 Value v;
|
|
424 v.putVstring(null);
|
|
425
|
|
426 Value vb;
|
|
427 vb.putVboolean(false);
|
|
428
|
|
429 classname = TEXT_RegExp;
|
|
430
|
|
431 //writef("Dregexp.Dregexp(pattern = '%ls', attributes = '%ls')\n", d_string_ptr(pattern), d_string_ptr(attributes));
|
|
432 Put(TEXT_source, &v, ReadOnly | DontDelete | DontEnum);
|
|
433 Put(TEXT_global, &vb, ReadOnly | DontDelete | DontEnum);
|
|
434 Put(TEXT_ignoreCase, &vb, ReadOnly | DontDelete | DontEnum);
|
|
435 Put(TEXT_multiline, &vb, ReadOnly | DontDelete | DontEnum);
|
|
436 Put(TEXT_lastIndex, 0.0, DontDelete | DontEnum);
|
|
437
|
|
438 source = Get(TEXT_source);
|
|
439 global = Get(TEXT_global);
|
|
440 ignoreCase = Get(TEXT_ignoreCase);
|
|
441 multiline = Get(TEXT_multiline);
|
|
442 lastIndex = Get(TEXT_lastIndex);
|
|
443
|
|
444 re = new RegExp(pattern, attributes);
|
|
445 if (re.errors == 0)
|
|
446 {
|
|
447 source.putVstring(pattern);
|
|
448 //writef("source = '%s'\n", source.x.string.toDchars());
|
|
449 global.putVboolean((re.attributes & RegExp.REA.global) != 0);
|
|
450 ignoreCase.putVboolean((re.attributes & RegExp.REA.ignoreCase) != 0);
|
|
451 multiline.putVboolean((re.attributes & RegExp.REA.multiline) != 0);
|
|
452 }
|
|
453 else
|
|
454 {
|
|
455 // have caller throw SyntaxError
|
|
456 }
|
|
457 }
|
|
458
|
|
459 this(Dobject prototype)
|
|
460 {
|
|
461 super(prototype);
|
|
462
|
|
463 Value v;
|
|
464 v.putVstring(null);
|
|
465
|
|
466 Value vb;
|
|
467 vb.putVboolean(false);
|
|
468
|
|
469 classname = TEXT_RegExp;
|
|
470
|
|
471 Put(TEXT_source, &v, ReadOnly | DontDelete | DontEnum);
|
|
472 Put(TEXT_global, &vb, ReadOnly | DontDelete | DontEnum);
|
|
473 Put(TEXT_ignoreCase, &vb, ReadOnly | DontDelete | DontEnum);
|
|
474 Put(TEXT_multiline, &vb, ReadOnly | DontDelete | DontEnum);
|
|
475 Put(TEXT_lastIndex, 0.0, DontDelete | DontEnum);
|
|
476
|
|
477 source = Get(TEXT_source);
|
|
478 global = Get(TEXT_global);
|
|
479 ignoreCase = Get(TEXT_ignoreCase);
|
|
480 multiline = Get(TEXT_multiline);
|
|
481 lastIndex = Get(TEXT_lastIndex);
|
|
482
|
|
483 re = new RegExp(null, null);
|
|
484 }
|
|
485
|
|
486 void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
|
|
487 {
|
|
488 // This is the same as calling RegExp.prototype.exec(str)
|
|
489 Value* v;
|
|
490
|
|
491 v = Get(TEXT_exec);
|
|
492 return v.toObject().Call(cc, this, ret, arglist);
|
|
493 }
|
|
494
|
|
495 static Dregexp isRegExp(Value* v)
|
|
496 {
|
|
497 Dregexp r;
|
|
498
|
|
499 if (!v.isPrimitive() && v.toObject().isDregexp())
|
|
500 {
|
|
501 r = cast(Dregexp)(v.toObject());
|
|
502 }
|
|
503 return r;
|
|
504 }
|
|
505
|
|
506 static void* exec(Dobject othis, Value* ret, Value[] arglist, int rettype)
|
|
507 {
|
|
508 //writef("Dregexp.exec(arglist.length = %d, rettype = %d)\n", arglist.length, rettype);
|
|
509
|
|
510 // othis must be a RegExp
|
|
511 if (!othis.isClass(TEXT_RegExp))
|
|
512 {
|
|
513 ret.putVundefined();
|
|
514 ErrInfo errinfo;
|
|
515 return RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
|
|
516 "RegExp.prototype.exec()");
|
|
517 }
|
|
518 else
|
|
519 {
|
|
520 d_string s;
|
|
521 Dregexp dr;
|
|
522 RegExp r;
|
|
523 Dregexp_constructor dc;
|
|
524 uint i;
|
|
525 d_int32 lasti;
|
|
526
|
|
527 if (arglist.length)
|
|
528 s = arglist[0].toString();
|
|
529 else
|
|
530 { Dfunction df;
|
|
531
|
|
532 df = Dregexp.getConstructor();
|
|
533 s = (cast(Dregexp_constructor)df).input.string;
|
|
534 }
|
|
535
|
|
536 dr = cast(Dregexp)othis;
|
|
537 r = dr.re;
|
|
538 dc = cast(Dregexp_constructor)Dregexp.getConstructor();
|
|
539
|
|
540 // Decide if we are multiline
|
|
541 if (dr.multiline.dbool)
|
|
542 r.attributes |= RegExp.REA.multiline;
|
|
543 else
|
|
544 r.attributes &= ~RegExp.REA.multiline;
|
|
545
|
|
546 if (r.attributes & RegExp.REA.global && rettype != EXEC_INDEX)
|
|
547 lasti = cast(int)dr.lastIndex.toInteger();
|
|
548 else
|
|
549 lasti = 0;
|
|
550
|
|
551 if (r.test(s, lasti))
|
|
552 { // Successful match
|
|
553 Value* lastv;
|
|
554 uint nmatches;
|
|
555
|
|
556 if (r.attributes & RegExp.REA.global && rettype != EXEC_INDEX)
|
|
557 {
|
|
558 dr.lastIndex.putVnumber(r.pmatch[0].rm_eo);
|
|
559 }
|
|
560
|
|
561 dc.input.putVstring(r.input);
|
|
562
|
|
563 s = r.input[r.pmatch[0].rm_so .. r.pmatch[0].rm_eo];
|
|
564 dc.lastMatch.putVstring(s);
|
|
565
|
|
566 s = r.input[0 .. r.pmatch[0].rm_so];
|
|
567 dc.leftContext.putVstring(s);
|
|
568
|
|
569 s = r.input[r.pmatch[0].rm_eo .. length];
|
|
570 dc.rightContext.putVstring(s);
|
|
571
|
|
572 dc.index.putVnumber(r.pmatch[0].rm_so);
|
|
573 dc.lastIndex.putVnumber(r.pmatch[0].rm_eo);
|
|
574
|
|
575 // Fill in $1..$9
|
|
576 lastv = &vundefined;
|
|
577 nmatches = 0;
|
|
578 for (i = 1; i <= 9; i++)
|
|
579 {
|
|
580 if (i <= r.re_nsub)
|
|
581 { int n;
|
|
582
|
|
583 // Use last 9 entries for $1..$9
|
|
584 n = i;
|
|
585 if (r.re_nsub > 9)
|
|
586 n += (r.re_nsub - 9);
|
|
587
|
|
588 if (r.pmatch[n].rm_so != -1)
|
|
589 { s = r.input[r.pmatch[n].rm_so .. r.pmatch[n].rm_eo];
|
|
590 dc.dollar[i].putVstring(s);
|
|
591 nmatches = i;
|
|
592 }
|
|
593 else
|
|
594 dc.dollar[i].putVundefined();
|
|
595 lastv = dc.dollar[i];
|
|
596 }
|
|
597 else
|
|
598 dc.dollar[i].putVundefined();
|
|
599 }
|
|
600 // Last substring in $1..$9, or "" if none
|
|
601 if (r.re_nsub)
|
|
602 Value.copy(dc.lastParen, lastv);
|
|
603 else
|
|
604 dc.lastParen.putVstring(null);
|
|
605
|
|
606 switch (rettype)
|
|
607 {
|
|
608 case EXEC_ARRAY:
|
|
609 {
|
|
610 Darray a = new Darray();
|
|
611
|
|
612 a.Put(TEXT_input, r.input, 0);
|
|
613 a.Put(TEXT_index, r.pmatch[0].rm_so, 0);
|
|
614 a.Put(TEXT_lastIndex, r.pmatch[0].rm_eo, 0);
|
|
615
|
|
616 a.Put(cast(d_uint32)0, dc.lastMatch, cast(uint)0);
|
|
617
|
|
618 // [1]..[nparens]
|
|
619 for (i = 1; i <= r.re_nsub; i++)
|
|
620 {
|
|
621 if (i > nmatches)
|
|
622 a.Put(i, TEXT_, 0);
|
|
623
|
|
624 // Reuse values already put into dc.dollar[]
|
|
625 else if (r.re_nsub <= 9)
|
|
626 a.Put(i, dc.dollar[i], 0);
|
|
627 else if (i > r.re_nsub - 9)
|
|
628 a.Put(i, dc.dollar[i - (r.re_nsub - 9)], 0);
|
|
629 else if (r.pmatch[i].rm_so == -1)
|
|
630 {
|
|
631 a.Put(i, &vundefined, 0);
|
|
632 }
|
|
633 else
|
|
634 {
|
|
635 s = r.input[r.pmatch[i].rm_so .. r.pmatch[i].rm_eo];
|
|
636 a.Put(i, s, 0);
|
|
637 }
|
|
638 }
|
|
639 ret.putVobject(a);
|
|
640 break;
|
|
641 }
|
|
642 case EXEC_STRING:
|
|
643 Value.copy(ret, dc.lastMatch);
|
|
644 break;
|
|
645
|
|
646 case EXEC_BOOLEAN:
|
|
647 ret.putVboolean(true); // success
|
|
648 break;
|
|
649
|
|
650 case EXEC_INDEX:
|
|
651 ret.putVnumber(r.pmatch[0].rm_so);
|
|
652 break;
|
|
653
|
|
654 default:
|
|
655 assert(0);
|
|
656 }
|
|
657 }
|
|
658 else // failed to match
|
|
659 {
|
|
660 //writef("failed\n");
|
|
661 switch (rettype)
|
|
662 {
|
|
663 case EXEC_ARRAY:
|
|
664 //writef("memcpy\n");
|
|
665 ret.putVnull(); // Return null
|
|
666 dr.lastIndex.putVnumber(0);
|
|
667 break;
|
|
668
|
|
669 case EXEC_STRING:
|
|
670 ret.putVstring(null);
|
|
671 dr.lastIndex.putVnumber(0);
|
|
672 break;
|
|
673
|
|
674 case EXEC_BOOLEAN:
|
|
675 ret.putVboolean(false);
|
|
676 dr.lastIndex.putVnumber(0);
|
|
677 break;
|
|
678
|
|
679 case EXEC_INDEX:
|
|
680 ret.putVnumber(-1.0);
|
|
681 // Do not set lastIndex
|
|
682 break;
|
|
683
|
|
684 default:
|
|
685 assert(0);
|
|
686 }
|
|
687 }
|
|
688 }
|
|
689 return null;
|
|
690 }
|
|
691
|
|
692 static Dfunction getConstructor()
|
|
693 {
|
|
694 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
695 assert(tc);
|
|
696 return tc.Dregexp_constructor;
|
|
697 }
|
|
698
|
|
699 static Dobject getPrototype()
|
|
700 {
|
|
701 ThreadContext* tc = ThreadContext.getThreadContext();
|
|
702 assert(tc);
|
|
703 return tc.Dregexp_prototype;
|
|
704 }
|
|
705
|
|
706 static void init(ThreadContext *tc)
|
|
707 {
|
|
708 tc.Dregexp_constructor = new Dregexp_constructor(tc);
|
|
709 tc.Dregexp_prototype = new Dregexp_prototype(tc);
|
|
710
|
|
711 version (none)
|
|
712 {
|
|
713 writef("tc.Dregexp_constructor = %x\n", tc.Dregexp_constructor);
|
|
714 uint *p;
|
|
715 p = cast(uint *)tc.Dregexp_constructor;
|
|
716 writef("p = %x\n", p);
|
|
717 if (p)
|
|
718 writef("*p = %x, %x, %x, %x\n", p[0], p[1], p[2], p[3]);
|
|
719 }
|
|
720
|
|
721 tc.Dregexp_constructor.Put(TEXT_prototype, tc.Dregexp_prototype, DontEnum | DontDelete | ReadOnly);
|
|
722 }
|
|
723 }
|