d2f73259c9ae822d6a940bf6123109ac5f115cc2
[m17n/m17n-lib-cs.git] / MPlist.cs
1 using System;
2 using System.Collections;
3 using System.IO;
4 using M17N;
5 using M17N.Core;
6
7 namespace M17N.Core
8 {
9   public class MPlist : IEnumerable
10   {
11     public MSymbol Key;
12     public object Val;
13     private MPlist next;
14
15     public MPlist ()
16       {
17         Key = MSymbol.nil;
18         Val = null;
19       }
20
21     public MPlist (FileStream stream)
22       {
23         MStreamReader reader = new MStreamReader (stream);
24         MSymbol key;
25         object val;
26         bool result = reader.ReadElement (out key, out val);
27
28         Key = key;
29         Val = val;
30         if (result)
31           next = new MPlist (reader);
32       }
33
34     public MPlist (FileStream stream, int count)
35       {
36         MStreamReader reader = new MStreamReader (stream);
37         MSymbol key;
38         object val;
39         bool result = reader.ReadElement (out key, out val);
40
41         Key = key;
42         Val = val;
43         if (result && --count > 0)
44           next = new MPlist (reader, count);
45         else
46           next = new MPlist ();
47       }
48
49     public MPlist (FileStream stream, MSymbol target, MSymbol stop)
50       {
51         MStreamReader reader = new MStreamReader (stream);
52         MSymbol key;
53         object val;
54         bool result;
55
56         Key = MSymbol.nil;
57         Val = null;
58         while (true)
59           {
60             result = reader.ReadElement (out key, out val);
61             if (! result)
62               return;
63             if (key == MSymbol.plist)
64               {
65                 MPlist plist = (MPlist) val;
66
67                 if (plist.IsSymbol)
68                   {
69                     if (plist.Symbol == stop)
70                       return;
71                     if (plist.Symbol == target)
72                       {
73                         Key = target;
74                         Val = val;
75                         next = new MPlist ();
76                         return;
77                       }
78                   }
79               }
80           }
81       }
82
83     public MPlist (MStreamReader reader)
84       {
85         MSymbol key;
86         object val;
87         bool result = reader.ReadElement (out key, out val);
88
89         Key = key;
90         Val = val;
91         if (result)
92           next = new MPlist (reader);
93       }
94
95     public MPlist (MStreamReader reader, int count)
96       {
97         MSymbol key;
98         object val;
99         bool result = reader.ReadElement (out key, out val);
100
101         Key = key;
102         Val = val;
103         if (result && --count > 0)
104           next = new MPlist (reader, count);
105         else
106           next = new MPlist ();
107       }
108
109     public MPlist (MStreamReader reader, MSymbol target, MSymbol stop)
110       {
111         MSymbol key;
112         object val;
113         bool result;
114
115         Key = MSymbol.nil;
116         Val = null;
117         while (true)
118           {
119             result = reader.ReadElement (out key, out val);
120             if (! result)
121               return;
122             if (key == MSymbol.plist)
123               {
124                 MPlist plist = (MPlist) val;
125
126                 if (plist.IsSymbol)
127                   {
128                     if (plist.Symbol == stop)
129                       return;
130                     if (plist.Symbol == target)
131                       {
132                         Key = target;
133                         Val = val;
134                         next = new MPlist ();
135                         return;
136                       }
137                   }
138               }
139           }
140       }
141
142     private MPlist (MSymbol key, object val)
143       {
144         Key = key;
145         Val = val;
146       }
147
148     public bool IsEmpty { get { return next == null; } }
149     public MPlist Next { get { return next; } }
150
151     internal bool IsSymbol { get { return Key == MSymbol.symbol; } }
152     internal bool IsMText { get { return Key == MSymbol.mtext; } }
153     internal bool IsPlist { get { return Key == MSymbol.plist; } }
154     internal bool IsInteger { get { return Key == MSymbol.integer; } }
155
156     internal MSymbol Symbol { get { return (MSymbol) Val; } }
157     internal MText Text { get { return (MText) Val; } }
158     internal MPlist Plist { get { return (MPlist) Val; } }
159     internal int Integer { get { return (int) Val; } }
160
161     public int Count
162     {
163       get
164         {
165           int i = 0;
166
167           for (MPlist p = this; p.next != null; i++, p = p.next);
168           return i;
169         }
170     }
171
172     public MPlist Clone ()
173     {
174       MPlist plist = new MPlist (), pl = plist;
175
176       for (MPlist p = this; p.next != null; p = p.next)
177         pl = pl.Add (p.Key, p.Val);
178       return plist;
179     }
180
181     public override string ToString ()
182     {
183         string str = "(";
184
185         for (MPlist p = this; ! p.IsEmpty; p = p.next)
186           {
187             if (p != this)
188               str += " ";
189             if (p.Key != MSymbol.symbol
190                 && p.Key != MSymbol.integer
191                 && p.Key != MSymbol.plist
192                 && p.Key != MSymbol.mtext)
193               str += p.Key + ":";
194             if (p.Key == MSymbol.mtext)
195               str += "\"" + p.Val + "\"";
196             else
197               str += p.Val;
198           }
199         return str + ")";
200     }
201
202     private MPlist find (MSymbol key)
203     {
204       MPlist p;
205
206       for (p = this; ! p.IsEmpty; p = p.next)
207         if (p.Key == key)
208           break;
209       return p;
210     }
211
212     public MPlist Find (MSymbol key)
213     {
214       MPlist p = find (key);
215
216       return (p.IsEmpty ? null : p);
217     }
218
219     public object Get (MSymbol key)
220     {
221       return find (key).Val;
222     }
223
224     internal MPlist Assq (MSymbol key)
225     {
226       foreach (MPlist p in this)
227         if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key)
228           return p;
229       return null;
230     }
231
232     private delegate MPlist MPlistDelegate (MSymbol key, object val);
233
234     private MPlist mplist_op (MPlistDelegate op, object val)
235     {
236       Type type = val.GetType ();
237
238       if (Object.ReferenceEquals (type, typeof (MSymbol)))
239         return op (MSymbol.symbol, val);
240       if (Object.ReferenceEquals (type, typeof (MText)))
241         return op (MSymbol.mtext, val);
242       if (Object.ReferenceEquals (type, typeof (MPlist)))
243         return op (MSymbol.plist, val);
244       if (Object.ReferenceEquals (type, typeof (int)))
245         return op (MSymbol.integer, val);
246       return op (MSymbol.t, val);
247     }
248
249     public MPlist Set (MSymbol key, object val)
250     {
251       if (IsEmpty)
252         Push (key, val);
253       else
254         Val = val;
255       return this;
256     }
257
258     public MPlist Set (object val)
259     {
260       return mplist_op (Set, val);
261     }
262
263     public MPlist Put (MSymbol key, object val)
264     {
265       return find (key).Set (key, val);
266     }
267
268     public MPlist Put (object val)
269     {
270       return mplist_op (Put, val);
271     }
272
273     public MPlist Push (MSymbol key, object val)
274     {
275       MPlist p = new MPlist (Key, Val);
276
277       p.next = this.next;
278       Key = key;
279       Val = val;
280       next = p;
281       return this;
282     }
283
284     public MPlist Push (object val)
285     {
286       return mplist_op (Push, val);
287     }
288
289     public object Pop (out MSymbol key)
290     {
291       key = Key;
292       if (IsEmpty)
293         return null;
294
295       object val = Val;
296
297       Key = next.Key;
298       Val = next.Val;
299       next = next.next;
300       return val;
301     }
302
303     public object Pop ()
304     {
305       MSymbol key;
306       return Pop (out key);
307     }
308
309     public MPlist Add (MSymbol key, object val)
310     {
311       MPlist p;
312
313       for (p = this; ! p.IsEmpty; p = p.next);
314       return p.Push (key, val);
315     }
316
317     public MPlist Clear ()
318     {
319       Key = MSymbol.nil;
320       Val = null;
321       next = null;
322       return this;
323     }
324
325     // Implement IEnumerable interface.
326     //   foreach (MPlist p in plist) { ... }
327
328     public virtual IEnumerator GetEnumerator ()
329     {
330       return new Enumerator (this);
331     }
332
333     private class Enumerator : IEnumerator
334     {
335       private MPlist plist;
336       private MPlist current;
337
338       internal Enumerator (MPlist plist)
339         {
340           this.plist = plist;
341         }
342
343       public object Current
344       {
345         get {
346           if (current == null || current.IsEmpty)
347             throw new InvalidOperationException ();
348           return current;
349         }
350       }
351
352       public void Reset ()
353       {
354         current = null;
355       }
356
357       public bool MoveNext ()
358       {
359         if (current == null)
360           current = plist;
361         else
362           current = current.next;
363         return (! current.IsEmpty);
364       }
365     }
366   }
367
368   public class MStreamReader : StreamReader
369   {
370     private static char[] escaped_char = new char[128];
371     private static int[] hexadecimal = new int[128];
372
373     public MStreamReader (Stream stream) : base (stream)
374       {
375       }
376
377     static MStreamReader ()
378       {
379         for (int i = 0; i < 128; i++)
380           escaped_char[i] = (char) i;
381         escaped_char['e'] = (char) 27;
382         escaped_char['b'] = '\b';
383         escaped_char['f'] = '\f';
384         escaped_char['n'] = '\n';
385         escaped_char['r'] = '\r';
386         escaped_char['t'] = '\t';
387         escaped_char['\\'] = '\\';
388         for (int i = 0; i < 128; i++)
389           hexadecimal[i] = -1;
390         for (int i = '0'; i <= '9'; i++)
391           hexadecimal[i] = i - '0';
392         for (int i = 'A'; i <= 'F'; i++)
393           hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
394       }
395
396     internal int PeekChar ()
397     {
398       bool comment = false;
399       int c;
400
401       while ((c = Peek ()) != -1)
402         {
403           if (comment)
404             {
405               if ((c = Read ()) == '\n')
406                 comment = false;
407             }
408           else
409             {
410               if (c == ';')
411                 comment = true;
412               else if (c != ' ' && c != '\t' && c != '\n')
413                 return c;
414               Read ();
415             }
416         }
417       return c;
418     }
419
420     internal int ReadHexadecimal ()
421     {
422       int i = 0, c;
423
424       while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
425         {
426           Read ();
427           i = (i * 16) + c;
428         }
429       return i;
430     }
431
432     internal int ReadInteger ()
433     {
434       int i = 0, c;
435
436       while ((c = Peek ()) >= '0' && c <= '9')
437         i = (i * 10) + (Read () - '0');
438       return i;
439     }
440
441     internal int ReadChar ()
442     {
443       int c = Read ();
444
445       if (c == '\\')
446         {
447           c = Read ();
448           if (c == -1)
449             return -1;
450           if (c == 'x' || c == 'u')
451             return ReadHexadecimal ();
452           if (c < 128)
453             c = escaped_char[c];
454         }
455       return c;
456     }
457
458     internal MText ReadMtext ()
459     {
460       MText mt = new MText ();
461       int c;
462
463       while ((c = Peek ()) != -1 && c != '"')
464         {
465           if (c == '\\')
466             {
467               c = ReadChar ();
468               if (Peek () == '\n')
469                 {
470                   ReadChar ();
471                   continue;
472                 }
473               if (c == -1)
474                 {
475                   mt.Cat ('\\');
476                   break;
477                 }
478               mt.Cat (c);
479             }
480           else
481             mt.Cat (Read ());
482         }
483       if (c == '"')
484         Read ();
485       return mt;
486     }
487
488     internal string ReadSymbolName ()
489     {
490       int c = Peek ();
491
492       if (c == -1 || c == '(' || c == ')' || c == ' ' || c == '\n' || c == '"')
493         return "";
494       Read ();
495       if (c == '\\')
496         {
497           c = Read ();
498           if (c == -1)
499             c = '\\';
500         }
501       return (char) c + ReadSymbolName ();
502     }
503
504     internal bool ReadElement (out MSymbol key, out object val)
505     {
506       int c = PeekChar ();
507
508       if (c == '(')
509         {
510           Read ();
511           val = new MPlist (this);
512           key = MSymbol.plist;
513         }
514       else if (c == '"')
515         {
516           Read ();
517           val = ReadMtext ();
518           key = MSymbol.mtext;
519         }
520       else if (c >= '0' && c <= '9')
521         {
522           int i = ReadInteger ();
523
524           val = i;
525           key = MSymbol.integer;
526         }
527       else if (c == '-')
528         {
529           Read ();
530           c = Peek ();
531           if (c >= '0' && c <= '9')
532             {
533               int i = ReadInteger ();
534               val = - i;
535               key = MSymbol.integer;
536             }
537           else
538             {
539               string str = ReadSymbolName ();
540
541               val = MSymbol.Of ("-" + str);
542               key = MSymbol.symbol;
543             }
544         }
545       else if (c == '?')
546         {
547           Read ();
548           val = ReadChar ();
549           key = MSymbol.integer;
550         }
551       else if (c == '#')
552         {
553           Read ();
554           if ((c = Peek ()) == 'x' || c == 'u')
555             {
556               Read ();
557               val = ReadHexadecimal ();
558               key = MSymbol.integer;
559             }
560           else
561             {
562               string str = ReadSymbolName ();
563
564               val = MSymbol.Of ("#" + (char) c + str);
565               key = MSymbol.symbol;
566             }
567         }
568       else if (c == -1 || c == ')')
569         {
570           if (c == ')')
571             Read ();
572           val = null;
573           key = MSymbol.nil;
574           return false;
575         }
576       else
577         {
578           val = MSymbol.Of (ReadSymbolName ());
579           key = MSymbol.symbol;
580         }
581       return true;
582     }
583   }
584 }