New test.
[mono.git] / mcs / class / System / System.Text.RegularExpressions / compiler.cs
1 //
2 // assembly:    System
3 // namespace:   System.Text.RegularExpressions
4 // file:        compiler.cs
5 //
6 // author:      Dan Lewis (dlewis@gmx.co.uk)
7 //              (c) 2002
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections;
32
33 namespace System.Text.RegularExpressions {
34         abstract class LinkRef {
35                 // empty
36         }
37                 
38         interface ICompiler {
39                 void Reset ();
40                 IMachineFactory GetMachineFactory ();
41
42                 // instruction emission
43
44                 void EmitFalse ();
45                 void EmitTrue ();
46
47                 // character matching
48
49                 void EmitCharacter (char c, bool negate, bool ignore, bool reverse);
50                 void EmitCategory (Category cat, bool negate, bool reverse);
51                 void EmitNotCategory (Category cat, bool negate, bool reverse);
52                 void EmitRange (char lo, char hi, bool negate, bool ignore, bool reverse);
53                 void EmitSet (char lo, BitArray set, bool negate, bool ignore, bool reverse);
54
55                 // other operators
56
57                 void EmitString (string str, bool ignore, bool reverse);
58                 void EmitPosition (Position pos);
59                 void EmitOpen (int gid);
60                 void EmitClose (int gid);
61                 void EmitBalanceStart(int gid, int balance, bool capture,  LinkRef tail);
62                 void EmitBalance ();
63                 void EmitReference (int gid, bool ignore, bool reverse);
64
65                 // constructs
66
67                 void EmitIfDefined (int gid, LinkRef tail);
68                 void EmitSub (LinkRef tail);
69                 void EmitTest (LinkRef yes, LinkRef tail);
70                 void EmitBranch (LinkRef next);
71                 void EmitJump (LinkRef target);
72                 void EmitRepeat (int min, int max, bool lazy, LinkRef until);
73                 void EmitUntil (LinkRef repeat);
74                 void EmitIn (LinkRef tail);
75                 void EmitInfo (int count, int min, int max);
76                 void EmitFastRepeat (int min, int max, bool lazy, LinkRef tail);
77                 void EmitAnchor (bool reverse, int offset, LinkRef tail);
78
79                 // event for the CILCompiler
80                 void EmitBranchEnd();
81                 void EmitAlternationEnd();
82
83                 LinkRef NewLink ();
84                 void ResolveLink (LinkRef link);
85         }
86
87         class InterpreterFactory : IMachineFactory {
88                 public InterpreterFactory (ushort[] pattern) {
89                         this.pattern = pattern;
90                 }
91                 
92                 public IMachine NewInstance () {
93                         return new Interpreter (pattern);
94                 }
95
96                 public int GroupCount {
97                         get { return pattern[1]; }
98                 }
99
100                 public IDictionary Mapping {
101                         get { return mapping; }
102                         set { mapping = value; }
103                 }
104
105                 private IDictionary mapping;
106                 private ushort[] pattern;
107         }
108
109         class PatternCompiler : ICompiler {
110                 public static ushort EncodeOp (OpCode op, OpFlags flags) {
111                         return (ushort)((int)op | ((int)flags & 0xff00));
112                 }
113
114                 public static void DecodeOp (ushort word, out OpCode op, out OpFlags flags) {
115                         op = (OpCode)(word & 0x00ff);
116                         flags = (OpFlags)(word & 0xff00);
117                 }
118
119                 public PatternCompiler () {
120                         pgm = new ArrayList ();
121                 }
122
123                 // ICompiler implementation
124
125                 public void Reset () {
126                         pgm.Clear ();
127                 }
128
129                 public IMachineFactory GetMachineFactory () {
130                         ushort[] image = new ushort[pgm.Count];
131                         pgm.CopyTo (image);
132
133                         return new InterpreterFactory (image);
134                 }
135
136                 public void EmitFalse () {
137                         Emit (OpCode.False);
138                 }
139
140                 public void EmitTrue () {
141                         Emit (OpCode.True);
142                 }
143
144                 void EmitCount (int count)
145                 {
146                         uint ucount = (uint) count;
147                         Emit ((ushort) (ucount & 0xFFFF)); // lo 16bits
148                         Emit ((ushort) (ucount >> 16));    // hi
149                 }
150
151                 public void EmitCharacter (char c, bool negate, bool ignore, bool reverse) {
152                         Emit (OpCode.Character, MakeFlags (negate, ignore, reverse, false));
153
154                         if (ignore)
155                                 c = Char.ToLower (c);
156
157                         Emit ((ushort)c);
158                 }
159
160                 public void EmitCategory (Category cat, bool negate, bool reverse) {
161                         Emit (OpCode.Category, MakeFlags (negate, false, reverse, false));
162                         Emit ((ushort)cat);
163                 }
164
165                 public void EmitNotCategory (Category cat, bool negate, bool reverse) {
166                         Emit (OpCode.NotCategory, MakeFlags (negate, false, reverse, false));
167                         Emit ((ushort)cat);
168                 }
169
170                 public void EmitRange (char lo, char hi, bool negate, bool ignore, bool reverse) {
171                         Emit (OpCode.Range, MakeFlags (negate, ignore, reverse, false));
172                         Emit ((ushort)lo);
173                         Emit ((ushort)hi);
174                 }
175
176                 public void EmitSet (char lo, BitArray set, bool negate, bool ignore, bool reverse) {
177                         Emit (OpCode.Set, MakeFlags (negate, ignore, reverse, false));
178                         Emit ((ushort)lo);
179
180                         int len = (set.Length + 0xf) >> 4;
181                         Emit ((ushort)len);
182
183                         int b = 0;
184                         while (len -- != 0) {
185                                 ushort word = 0;
186                                 for (int i = 0; i < 16; ++ i) {
187                                         if (b >= set.Length)
188                                                 break;
189                                 
190                                         if (set[b ++])
191                                                 word |= (ushort)(1 << i);
192                                 }
193
194                                 Emit (word);
195                         }
196                 }
197
198                 public void EmitString (string str, bool ignore, bool reverse) {
199                         Emit (OpCode.String, MakeFlags (false, ignore, reverse, false));
200                         int len = str.Length;
201                         Emit ((ushort)len);
202
203                         if (ignore)
204                                 str = str.ToLower ();
205                         
206                         for (int i = 0; i < len; ++ i)
207                                 Emit ((ushort)str[i]);
208                 }
209
210                 public void EmitPosition (Position pos) {
211                         Emit (OpCode.Position, 0);
212                         Emit ((ushort)pos);
213                 }
214
215                 public void EmitOpen (int gid) {
216                         Emit (OpCode.Open);
217                         Emit ((ushort)gid);
218                 }
219
220                 public void EmitClose (int gid) {
221                         Emit (OpCode.Close);
222                         Emit ((ushort)gid);
223                 }
224
225                
226
227                 public void EmitBalanceStart (int gid, int balance, bool capture, LinkRef tail) {
228                         BeginLink (tail);
229                         Emit (OpCode.BalanceStart);
230                         Emit ((ushort)gid);
231                         Emit ((ushort)balance);
232                         Emit ((ushort)(capture ? 1 : 0));
233                         EmitLink (tail);
234                 }
235
236                 public void EmitBalance () {
237                         Emit (OpCode.Balance);
238                 }
239
240                 public void EmitReference (int gid, bool ignore, bool reverse) {
241                         Emit (OpCode.Reference, MakeFlags (false, ignore, reverse, false));
242                         Emit ((ushort)gid);
243                 }
244
245                 public void EmitIfDefined (int gid, LinkRef tail) {
246                         BeginLink (tail);
247                         Emit (OpCode.IfDefined);
248                         EmitLink (tail);
249                         Emit ((ushort)gid);
250                 }
251
252                 public void EmitSub (LinkRef tail) {
253                         BeginLink (tail);
254                         Emit (OpCode.Sub);
255                         EmitLink (tail);
256                 }
257
258                 public void EmitTest (LinkRef yes, LinkRef tail) {
259                         BeginLink (yes);
260                         BeginLink (tail);
261                         Emit (OpCode.Test);
262                         EmitLink (yes);
263                         EmitLink (tail);
264                 }
265
266                 public void EmitBranch (LinkRef next) {
267                         BeginLink (next);
268                         Emit (OpCode.Branch, 0);
269                         EmitLink (next);
270                 }
271
272                 public void EmitJump (LinkRef target) {
273                         BeginLink (target);
274                         Emit (OpCode.Jump, 0);
275                         EmitLink (target);
276                 }
277
278                 public void EmitRepeat (int min, int max, bool lazy, LinkRef until) {
279                         BeginLink (until);
280                         Emit (OpCode.Repeat, MakeFlags (false, false, false, lazy));
281                         EmitLink (until);
282                         EmitCount (min);
283                         EmitCount (max);
284                 }
285
286                 public void EmitUntil (LinkRef repeat) {
287                         ResolveLink (repeat);
288                         Emit (OpCode.Until);
289                 }
290
291                 public void EmitFastRepeat (int min, int max, bool lazy, LinkRef tail) {
292                         BeginLink (tail);
293                         Emit (OpCode.FastRepeat, MakeFlags (false, false, false, lazy));
294                         EmitLink (tail);
295                         EmitCount (min);
296                         EmitCount (max);
297                 }
298
299                 public void EmitIn (LinkRef tail) {
300                         BeginLink (tail);
301                         Emit (OpCode.In);
302                         EmitLink (tail);
303                 }
304
305                 public void EmitAnchor (bool reverse, int offset, LinkRef tail) {
306                         BeginLink (tail);
307                         Emit (OpCode.Anchor, MakeFlags(false, false, reverse, false));
308                         EmitLink (tail);
309                         Emit ((ushort)offset);
310                 }
311
312                 public void EmitInfo (int count, int min, int max) {
313                         Emit (OpCode.Info);
314                         EmitCount (count);
315                         EmitCount (min);
316                         EmitCount (max);
317                 }
318
319                 public LinkRef NewLink () {
320                         return new PatternLinkStack ();
321                 }
322                 
323                 public void ResolveLink (LinkRef lref) {
324                         PatternLinkStack stack = (PatternLinkStack)lref;
325                 
326                         while (stack.Pop ())
327                                 pgm[stack.OffsetAddress] = (ushort)stack.GetOffset (CurrentAddress);
328                 }
329
330                 public void EmitBranchEnd(){}
331                 public void EmitAlternationEnd(){}
332
333                 // private members
334
335                 private static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) {
336                         OpFlags flags = 0;
337                         if (negate) flags |= OpFlags.Negate;
338                         if (ignore) flags |= OpFlags.IgnoreCase;
339                         if (reverse) flags |= OpFlags.RightToLeft;
340                         if (lazy) flags |= OpFlags.Lazy;
341
342                         return flags;
343                 }
344                 
345                 private void Emit (OpCode op) {
346                         Emit (op, (OpFlags)0);
347                 }
348
349                 private void Emit (OpCode op, OpFlags flags) {
350                         Emit (EncodeOp (op, flags));
351                 }
352
353                 private void Emit (ushort word) {
354                         pgm.Add (word);
355                 }
356
357                 private int CurrentAddress {
358                         get { return pgm.Count; }
359                 }
360
361                 private void BeginLink (LinkRef lref) {
362                         PatternLinkStack stack = (PatternLinkStack)lref;
363                         stack.BaseAddress = CurrentAddress;
364                 }
365
366                 private void EmitLink (LinkRef lref) {
367                         PatternLinkStack stack = (PatternLinkStack)lref;
368                         stack.OffsetAddress = CurrentAddress;
369                         Emit ((ushort)0);       // placeholder
370                         stack.Push ();
371                 }
372
373
374                 private class PatternLinkStack : LinkStack {
375                         public PatternLinkStack () {
376                         }
377                 
378                         public int BaseAddress {
379                                 set { link.base_addr = value; }
380                         }
381
382                         public int OffsetAddress {
383                                 get { return link.offset_addr; }
384                                 set { link.offset_addr = value; }
385                         }
386
387                         public int GetOffset (int target_addr) {
388                                 return target_addr - link.base_addr;
389                         }
390
391                         // LinkStack implementation
392
393                         protected override object GetCurrent () { return link; }
394                         protected override void SetCurrent (object l) { link = (Link)l; }
395
396                         private struct Link {
397                                 public int base_addr;
398                                 public int offset_addr;
399                         }
400
401                         Link link;
402                 }
403
404                 private ArrayList pgm;
405         }
406
407         abstract class LinkStack : LinkRef {
408                 public LinkStack () {
409                         stack = new Stack ();
410                 }
411
412                 public void Push () {
413                         stack.Push (GetCurrent ());
414                 }
415
416                 public bool Pop () {
417                         if (stack.Count > 0) {
418                                 SetCurrent (stack.Pop ());
419                                 return true;
420                         }
421
422                         return false;
423                 }
424
425                 protected abstract object GetCurrent ();
426                 protected abstract void SetCurrent (object l);
427
428                 private Stack stack;
429         }
430
431         //Used by CILCompiler and Interpreter
432         internal struct Mark {
433                 public int Start, End;
434                 public int Previous;
435                 
436                 public bool IsDefined {
437                         get { return Start >= 0 && End >= 0; }
438                 }
439                 
440                 public int Index {
441                         get { return Start < End ? Start : End; }
442                 }
443                 
444                 public int Length {
445                         get { return Start < End ? End - Start : Start - End; }
446                 }
447         }
448
449 }