Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Regexp.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:29:50 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /*
2 Copyright(C) 2001-2002 arton
3
4 Permission is granted for use, copying, modification, distribution,
5 and distribution of modified versions of this work as long as the
6 above copyright notice is included.
7 */
8
9 using System;
10 using System.Diagnostics;
11 using System.Collections;
12 using System.IO;
13 using System.Text;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Text.RegularExpressions;
17
18 namespace arton.NETRuby
19 {
20 public class RRegexp : RBasic, ICloneable
21 {
22 public RRegexp(NetRuby rb, RMetaObject meta) :
23 base(rb, meta)
24 {
25 regex = null;
26 }
27 Regex regex;
28
29 public string Source
30 {
31 get { Check(); return regex.ToString(); }
32 }
33 public bool IsCaseFold
34 {
35 get { Check(); return (regex.Options & RegexOptions.IgnoreCase) != 0; }
36 }
37 internal Regex Regex
38 {
39 get { return regex; }
40 }
41 public int Search(string s, int pos, bool rev, bool stringTainted)
42 {
43 if (pos > s.Length) return -1;
44
45 RThread th = ruby.GetCurrentContext();
46 Check();
47 if (ruby.cRegexp.IsRecompileNeed)
48 checkPreparation();
49 Regex re = regex;
50 if (rev)
51 {
52 re = new Regex(re.ToString(), re.Options | RegexOptions.RightToLeft);
53 }
54 Match m = re.Match(s, pos);
55 if (m.Success == false)
56 {
57 th.BackRef = null;
58 return -1;
59 }
60 RMatchData mt = (RMatchData)th.BackRef;
61 if (mt == null || mt.Test(RRegexpClass.MatchBusy))
62 {
63 mt = new RMatchData(ruby, s, m);
64 }
65 else
66 {
67 if (th.safeLevel >= 3)
68 mt.Taint();
69 else
70 mt.Untaint();
71 mt.SetData(s, m);
72 }
73 th.BackRef = mt;
74 mt.Infect(this);
75 if (stringTainted) mt.Taint();
76 return m.Index;
77 }
78 public override object Inspect()
79 {
80 Check();
81 StringBuilder sb = new StringBuilder();
82 sb.AppendFormat("/{0}/", regex.ToString());
83 RegexOptions opt = regex.Options;
84 if ((opt & RegexOptions.Multiline) != 0)
85 sb.Append("m");
86 if ((opt & RegexOptions.IgnoreCase) != 0)
87 sb.Append("i");
88 if ((opt & RegexOptions.IgnorePatternWhitespace) != 0)
89 sb.Append("x");
90 string s = sb.ToString();
91 if (IsTainted)
92 return new RString(ruby, s, true);
93 return s;
94 }
95 public object Clone()
96 {
97 return MemberwiseClone();
98 }
99
100 internal void Check()
101 {
102 if (regex == null)
103 throw new eTypeError("uninitialized Regexp");
104 }
105
106 internal void Initialize(RRegexp r, RegexOptions fl)
107 {
108 regex = r.regex;
109 if (regex.Options != fl)
110 {
111 regex = new Regex(regex.ToString(), fl);
112 }
113 }
114 internal void Initialize(string s, RegexOptions fl)
115 {
116 regex = new Regex(s, fl);
117 }
118
119 public override bool Equals(object o)
120 {
121 if (base.Equals(o)) return true;
122 if (o is RRegexp == false) return false;
123 RRegexp re = (RRegexp)o;
124 Check();
125 re.Check();
126 if (re.regex.ToString() != regex.ToString() || re.regex.Options != regex.Options)
127 return false;
128 return true;
129 }
130 public override int GetHashCode() // for voiding CS0659 warning.
131 {
132 return base.GetHashCode();
133 }
134 void checkPreparation()
135 {
136 bool needRecompile = false;
137 Check();
138 RegexOptions options = regex.Options;
139 bool globalSetting = ruby.cRegexp.IsIgnoreCase;
140 if (globalSetting && (options & RegexOptions.IgnoreCase) == 0)
141 {
142 options |= RegexOptions.IgnoreCase;
143 needRecompile = true;
144 }
145 if (!globalSetting && (options & RegexOptions.IgnoreCase) != 0)
146 {
147 options &= ~RegexOptions.IgnoreCase;
148 needRecompile = true;
149 }
150 if (needRecompile)
151 {
152 regex = new Regex(regex.ToString(), options);
153 }
154 }
155 }
156
157 public class RMatchData : RData
158 {
159 internal RMatchData(NetRuby rb, string s, Match m) :
160 base(rb, rb.cMatch)
161 {
162 SetData(s, m);
163 }
164 internal void SetData(string s, Match m)
165 {
166 match = m;
167 target = s;
168 }
169 public Match Match
170 {
171 get { return match; }
172 }
173 public override RString ToRString()
174 {
175 string s = this[0];
176 RString r = new RString(ruby, (s == null) ? String.Empty : s);
177 if (IsTainted)
178 r.Taint();
179 return r;
180 }
181 public override RArray ToArray()
182 {
183 bool b = IsTainted;
184 RArray a = new RArray(ruby, true);
185 GroupCollection g = match.Groups;
186 for (int i = 0; i < g.Count; i++)
187 {
188 string s = g[i].Value;
189 if (b)
190 a.Add(new RString(ruby, s, b));
191 else
192 a.Add(s);
193 }
194 if (b)
195 a.Taint();
196 return a;
197 }
198 public string this[int index]
199 {
200 get {
201 if (match == null) return null;
202 if (index == 0)
203 return match.ToString();
204 GroupCollection col = match.Groups;
205 if (index >= col.Count) return null;
206 if (index < 0)
207 {
208 index += col.Count;
209 if (index <= 0) return null;
210 }
211 return col[index].Value;
212 }
213 }
214 public string Pre
215 {
216 get { return (match == null) ? null : target.Substring(0, match.Index); }
217 }
218 public string Post
219 {
220 get { return (match == null) ? null : target.Substring(match.Index + match.Length); }
221 }
222 public string Last
223 {
224 get {
225 if (match == null) return null;
226 GroupCollection col = match.Groups;
227 if (col.Count == 0) return null;
228 return col[col.Count - 1].Value;
229 }
230 }
231 public int Count
232 {
233 get { return (match == null) ? 0 : match.Groups.Count; }
234 }
235 public string Sub(string str, string src)
236 {
237 StringBuilder val = new StringBuilder();
238 int p = 0;
239 int no;
240 int i;
241 for (i = 0; i < str.Length;)
242 {
243 int ix = i;
244 char c = str[i++];
245 if (c != '\\') continue;
246 val.Append(str, p, ix - p);
247 c = str[i++];
248 p = i;
249 switch (c)
250 {
251 case '0': case '1': case '2': case '3': case '4':
252 case '5': case '6': case '7': case '8': case '9':
253 no = c - '0';
254 break;
255 case '&':
256 no = 0;
257 break;
258 case '`':
259 val.Append(src, 0, match.Index);
260 continue;
261 case '\'':
262 val.Append(src, match.Length, src.Length - match.Length);
263 continue;
264 case '+':
265 no = match.Groups.Count - 1;
266 while (match.Groups[no].Index == -1 && no > 0) no--;
267 if (no == 0) continue;
268 break;
269 case '\\':
270 val.Append('\\');
271 continue;
272 default:
273 val.Append(str, i - 2, 2);
274 continue;
275 }
276 if (no >= 0)
277 {
278 if (no >= match.Groups.Count) continue;
279 if (match.Groups[no].Index == -1) continue;
280 val.Append(src, match.Groups[no].Index, match.Groups[no].Length);
281 }
282 }
283 if (p < str.Length)
284 {
285 val.Append(str, p, str.Length - p);
286 }
287 return val.ToString();
288 }
289
290 void CheckOffset(int i)
291 {
292 if (i < 0 || i >= match.Groups.Count)
293 throw new eIndexError(String.Format("index {0} out of matches", i));
294 }
295 public RArray Offset(int i)
296 {
297 CheckOffset(i);
298 ArrayList ar = new ArrayList();
299 Group g = match.Groups[i];
300 if (g.Index < 0)
301 {
302 ar.Add(null);
303 ar.Add(null);
304 }
305 else
306 {
307 ar.Add(g.Index);
308 ar.Add(g.Index + g.Length);
309 }
310 return new RArray(ruby, ar);
311 }
312 public int Begin(int i)
313 {
314 CheckOffset(i);
315 Group g = match.Groups[i];
316 return g.Index;
317 }
318 public int End(int i)
319 {
320 CheckOffset(i);
321 Group g = match.Groups[i];
322 return g.Index + g.Length;
323 }
324 Match match;
325 string target;
326 }
327
328 public class RRegexpClass : RClass
329 {
330 private RRegexpClass(NetRuby rb) :
331 base(rb, "Regexp", rb.cObject)
332 {
333 ignoreCase = false;
334 recompileNeed = false;
335 }
336 public bool IsIgnoreCase
337 {
338 get { return ignoreCase; }
339 set {
340 if (value != ignoreCase)
341 {
342 ignoreCase = value;
343 recompileNeed = true;
344 }
345 }
346 }
347 internal bool IsRecompileNeed
348 {
349 get { return recompileNeed; }
350 }
351
352 bool ignoreCase;
353 bool recompileNeed;
354
355 internal const FL MatchBusy = FL.USER2;
356 internal const FL CaseState = FL.USER0;
357
358 internal static void matchBusy(object match)
359 {
360 if (match is RBasic)
361 {
362 ((RBasic)match).Set(MatchBusy);
363 }
364 }
365
366 static private object matchGetter(uint id, GlobalEntry gb, NetRuby rb)
367 {
368 RThread th = rb.GetCurrentContext();
369 object o = th.BackRef;
370 matchBusy(o);
371 return o;
372 }
373 static private void matchSetter(object val, uint id, GlobalEntry gb, NetRuby rb)
374 {
375 rb.CheckType(val, typeof(RMatchData));
376 RThread th = rb.GetCurrentContext();
377 th.BackRef = val;
378 }
379 static private object lastMatchGetter(uint id, GlobalEntry gb, NetRuby rb)
380 {
381 RThread th = rb.GetCurrentContext();
382 RMatchData m = (RMatchData)th.BackRef;
383 if (m == null) return null;
384 string s = m[0];
385 if (m.IsTainted)
386 return new RString(rb, s, true);
387 return s;
388 }
389 static private object preMatchGetter(uint id, GlobalEntry gb, NetRuby rb)
390 {
391 RThread th = rb.GetCurrentContext();
392 RMatchData m = (RMatchData)th.BackRef;
393 if (m == null) return null;
394 string s = m.Pre;
395 if (m.IsTainted)
396 return new RString(rb, s, true);
397 return s;
398 }
399 static private object postMatchGetter(uint id, GlobalEntry gb, NetRuby rb)
400 {
401 RThread th = rb.GetCurrentContext();
402 RMatchData m = (RMatchData)th.BackRef;
403 if (m == null) return null;
404 string s = m.Post;
405 if (m.IsTainted)
406 return new RString(rb, s, true);
407 return s;
408 }
409 static private object lastParenGetter(uint id, GlobalEntry gb, NetRuby rb)
410 {
411 RThread th = rb.GetCurrentContext();
412 RMatchData m = (RMatchData)th.BackRef;
413 if (m == null) return null;
414 string s = m.Last;
415 if (m.IsTainted)
416 return new RString(rb, s, true);
417 return s;
418 }
419 static private object iCaseGetter(uint id, GlobalEntry gb, NetRuby rb)
420 {
421 return rb.cRegexp.ignoreCase;
422 }
423 static private void iCaseSetter(object val, uint id, GlobalEntry gb, NetRuby rb)
424 {
425 rb.cRegexp.IsIgnoreCase = RBasic.RTest(val);
426 }
427 static private object kCodeGetter(uint id, GlobalEntry gb, NetRuby rb)
428 {
429 return "none";
430 }
431 static private void kCodeSetter(object val, uint id, GlobalEntry gb, NetRuby rb)
432 {
433 }
434
435 static internal object s_new(RBasic r, params object[] args)
436 {
437 RRegexp re = new RRegexp(r.ruby, (RMetaObject)r);
438 r.ruby.CallInit(re, args);
439 return re;
440 }
441 static internal object s_quote(RBasic r, params object[] args)
442 {
443 if (args.Length < 1 || args.Length > 2)
444 throw new eArgError("wront # of argument");
445 string p = RString.ToString(r.ruby, args[0]);
446 return Regex.Escape(p);
447 }
448 static internal object initialize(RBasic r, params object[] args)
449 {
450 if (args.Length < 1 || args.Length > 3)
451 throw new eArgError("wrong # of argument");
452 RegexOptions flag = RegexOptions.None;
453 if (args.Length >= 2)
454 {
455 if (args[1] is int || args[1] is RegexOptions) flag = (RegexOptions)(int)args[1];
456 else if (args[1] is RFixnum) flag = (RegexOptions)((RFixnum)args[1]).ToInt();
457 else if (RBasic.RTest(args[1])) flag = RegexOptions.IgnoreCase;
458 }
459 if (args.Length == 3)
460 {
461 // ignore char set
462 }
463 NetRuby ruby = r.ruby;
464 RRegexp self = (RRegexp)r;
465 if (args[0] is RRegexp)
466 {
467 RRegexp re = (RRegexp)args[0];
468 re.Check();
469 self.Initialize(re, flag);
470 }
471 else
472 {
473 string p = RString.ToString(ruby, args[0]);
474 self.Initialize(p, flag);
475 }
476 return self;
477 }
478 static internal object match(RBasic r, params object[] args)
479 {
480 if (args[0] == null) return null;
481 NetRuby rb = r.ruby;
482 string s = RString.ToString(rb, args[0]);
483 bool infect = false;
484 if (args[0] is RBasic && ((RBasic)args[0]).IsTainted)
485 infect = true;
486 int start = ((RRegexp)r).Search(s, 0, false, infect);
487 if (start < 0)
488 return null;
489 return start;
490 }
491 static internal object match2(RBasic r, params object[] args)
492 {
493 throw new NotSupportedException("Deprecated Method");
494 }
495 static private object s_lastmatch(RBasic r, params object[] args)
496 {
497 RThread th = r.ruby.GetCurrentContext();
498 RMatchData m = (RMatchData)th.BackRef;
499 if (m == null) return null;
500 string s = m[0];
501 if (m.IsTainted)
502 return new RString(r.ruby, s, true);
503 return s;
504 }
505 static internal object source(RBasic r, params object[] args)
506 {
507 string s = ((RRegexp)r).Source;
508 if (r.IsTainted)
509 return new RString(r.ruby, s, true);
510 return s;
511 }
512 static internal object kcode_m(RBasic r, params object[] args)
513 {
514 return "none";
515 }
516 static internal object casefold_p(RBasic r, params object[] args)
517 {
518 return ((RRegexp)r).IsCaseFold;
519 }
520 static internal object match_m(RBasic r, params object[] args)
521 {
522 object o = match(r, args);
523 if (o == null) return null;
524 RThread th = r.ruby.GetCurrentContext();
525 o = th.BackRef;
526 matchBusy(o);
527 return o;
528 }
529 static internal object match_size(RBasic r, params object[] args)
530 {
531 return ((RMatchData)r).Count;
532 }
533 static internal object match_offset(RBasic r, params object[] args)
534 {
535 NetRuby ruby = r.ruby;
536 int i = RInteger.ToInt(r.ruby, args[0]);
537 return ((RMatchData)r).Offset(i);
538 }
539 static internal object match_begin(RBasic r, params object[] args)
540 {
541 NetRuby ruby = r.ruby;
542 int i = RInteger.ToInt(r.ruby, args[0]);
543 return ((RMatchData)r).Begin(i);
544 }
545 static internal object match_end(RBasic r, params object[] args)
546 {
547 NetRuby ruby = r.ruby;
548 int i = RInteger.ToInt(r.ruby, args[0]);
549 return ((RMatchData)r).End(i);
550 }
551 static internal object match_to_s(RBasic r, params object[] args)
552 {
553 return ((RMatchData)r).ToRString();
554 }
555 static internal object match_string(RBasic r, params object[] args)
556 {
557 RString rs = ((RMatchData)r).ToRString();
558 rs.Freeze();
559 return rs;
560 }
561 static internal object match_aref(RBasic r, params object[] args)
562 {
563 object[] argv = new object[2];
564 NetRuby rb = r.ruby;
565 rb.ScanArgs(args, "11", argv);
566 if (argv[1] != null)
567 return ((RMatchData)r).ToArray().ARef(args);
568 return ((RMatchData)r)[RInteger.ToInt(rb, args[0])];
569 }
570 static internal object match_to_a(RBasic r, params object[] args)
571 {
572 return ((RMatchData)r).ToArray();
573 }
574 static internal object match_pre(RBasic r, params object[] args)
575 {
576 return ((RMatchData)r).Pre;
577 }
578 static internal object match_post(RBasic r, params object[] args)
579 {
580 return ((RMatchData)r).Post;
581 }
582 static internal void Init(NetRuby rb)
583 {
584 rb.eRegexpError = rb.DefineClass("RegexpError", rb.eStandardError);
585
586 rb.DefineVirtualVariable("$~",
587 new GlobalEntry.Getter(matchGetter),
588 new GlobalEntry.Setter(matchSetter));
589 rb.DefineVirtualVariable("$&",
590 new GlobalEntry.Getter(lastMatchGetter), null);
591 rb.DefineVirtualVariable("$`",
592 new GlobalEntry.Getter(preMatchGetter), null);
593 rb.DefineVirtualVariable("$'",
594 new GlobalEntry.Getter(postMatchGetter), null);
595 rb.DefineVirtualVariable("$+",
596 new GlobalEntry.Getter(lastParenGetter), null);
597 rb.DefineVirtualVariable("$=",
598 new GlobalEntry.Getter(iCaseGetter),
599 new GlobalEntry.Setter(iCaseSetter));
600 rb.DefineVirtualVariable("$KCODE",
601 new GlobalEntry.Getter(kCodeGetter),
602 new GlobalEntry.Setter(kCodeSetter));
603 rb.DefineVirtualVariable("$-K",
604 new GlobalEntry.Getter(kCodeGetter),
605 new GlobalEntry.Setter(kCodeSetter));
606
607 RRegexpClass reg = new RRegexpClass(rb);
608 reg.DefineClass("Regexp", rb.cObject);
609 rb.cRegexp = reg;
610
611 reg.DefineSingletonMethod("new", new RMethod(s_new), -1);
612 reg.DefineSingletonMethod("compile", new RMethod(s_new), -1);
613 reg.DefineSingletonMethod("quote", new RMethod(s_quote), -1);
614 reg.DefineSingletonMethod("escape", new RMethod(s_quote), -1);
615 reg.DefineSingletonMethod("last_match", new RMethod(s_lastmatch), 0);
616
617 reg.DefineMethod("initialize", new RMethod(initialize), -1);
618 reg.DefineMethod("=~", new RMethod(match), 1);
619 reg.DefineMethod("===", new RMethod(match), 1);
620 reg.DefineMethod("~", new RMethod(match2), 0);
621 reg.DefineMethod("match", new RMethod(match_m), 1);
622 reg.DefineMethod("source", new RMethod(source), 0);
623 reg.DefineMethod("casefold?", new RMethod(casefold_p), 0);
624 reg.DefineMethod("kcode", new RMethod(kcode_m), 0);
625
626 reg.DefineConst("IGNORECASE", RegexOptions.IgnoreCase);
627 reg.DefineConst("EXTENDED", RegexOptions.IgnorePatternWhitespace);
628 reg.DefineConst("MULTILINE", RegexOptions.Multiline);
629
630 RClass md = rb.DefineClass("MatchData", rb.cObject);
631 rb.DefineGlobalConst("MatchingData", md);
632 rb.cMatch = md;
633 rb.ClassOf(md).UndefMethod("new");
634 md.DefineMethod("size", new RMethod(match_size), 0);
635 md.DefineMethod("length", new RMethod(match_size), 0);
636 md.DefineMethod("offset", new RMethod(match_offset), 1);
637 md.DefineMethod("begin", new RMethod(match_begin), 1);
638 md.DefineMethod("end", new RMethod(match_end), 1);
639 md.DefineMethod("to_a", new RMethod(match_to_a), 0);
640 md.DefineMethod("[]", new RMethod(match_aref), -1);
641 md.DefineMethod("pre_match", new RMethod(match_pre), 0);
642 md.DefineMethod("post_match", new RMethod(match_post), 0);
643 md.DefineMethod("to_s", new RMethod(match_to_s), 0);
644 md.DefineMethod("string", new RMethod(match_string), 0);
645 }
646 }
647 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26