3c9b140860d8e5bd51759f48ad46e7d66a9f0dc2
[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     private 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     private 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     private 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     private class MStreamReader : StreamReader
368     {
369       private static char[] escaped_char = new char[128];
370       private static int[] hexadecimal = new int[128];
371
372       public MStreamReader (Stream stream) : base (stream)
373         {
374         }
375
376       static MStreamReader ()
377         {
378           for (int i = 0; i < 128; i++)
379             escaped_char[i] = (char) i;
380           escaped_char['e'] = (char) 27;
381           escaped_char['b'] = '\b';
382           escaped_char['f'] = '\f';
383           escaped_char['n'] = '\n';
384           escaped_char['r'] = '\r';
385           escaped_char['t'] = '\t';
386           escaped_char['\\'] = '\\';
387           for (int i = 0; i < 128; i++)
388             hexadecimal[i] = -1;
389           for (int i = '0'; i <= '9'; i++)
390             hexadecimal[i] = i - '0';
391           for (int i = 'A'; i <= 'F'; i++)
392             hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
393         }
394
395       private int PeekChar ()
396       {
397         bool comment = false;
398         int c;
399
400         while ((c = Peek ()) != -1)
401           {
402             if (comment)
403               {
404                 if ((c = Read ()) == '\n')
405                   comment = false;
406               }
407             else
408               {
409                 if (c == ';')
410                   comment = true;
411                 else if (c != ' ' && c != '\t' && c != '\n')
412                   return c;
413                 Read ();
414               }
415           }
416         return c;
417       }
418
419       private int ReadHexadecimal ()
420       {
421         int i = 0, c;
422
423         while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
424           {
425             Read ();
426             i = (i * 16) + c;
427           }
428         return i;
429       }
430
431       private int ReadInteger ()
432       {
433         int i = 0, c;
434
435         while ((c = Peek ()) >= '0' && c <= '9')
436           i = (i * 10) + (Read () - '0');
437         return i;
438       }
439
440       private int ReadChar ()
441       {
442         int c = Read ();
443
444         if (c == '\\')
445           {
446             c = Read ();
447             if (c == -1)
448               return -1;
449             if (c == 'x' || c == 'u')
450               return ReadHexadecimal ();
451             if (c < 128)
452               c = escaped_char[c];
453           }
454         return c;
455       }
456
457       private MText ReadMtext ()
458       {
459         MText mt = new MText ();
460         int c;
461
462         while ((c = Peek ()) != -1 && c != '"')
463           {
464             if (c == '\\')
465               {
466                 c = ReadChar ();
467                 if (Peek () == '\n')
468                   {
469                     ReadChar ();
470                     continue;
471                   }
472                 if (c == -1)
473                   {
474                     mt.Cat ('\\');
475                     break;
476                   }
477                 mt.Cat (c);
478               }
479             else
480               mt.Cat (Read ());
481           }
482         if (c == '"')
483           Read ();
484         return mt;
485       }
486
487       private string ReadSymbolName ()
488       {
489         int c = Peek ();
490
491         if (c == -1 || c == '(' || c == ')' || c == ' ' || c == '\n' || c == '"')
492           return "";
493         Read ();
494         if (c == '\\')
495           {
496             c = Read ();
497             if (c == -1)
498               c = '\\';
499           }
500         return (char) c + ReadSymbolName ();
501       }
502
503       public bool ReadElement (out MSymbol key, out object val)
504       {
505         int c = PeekChar ();
506
507         if (c == '(')
508           {
509             Read ();
510             val = new MPlist (this);
511             key = MSymbol.plist;
512           }
513         else if (c == '"')
514           {
515             Read ();
516             val = ReadMtext ();
517             key = MSymbol.mtext;
518           }
519         else if (c >= '0' && c <= '9')
520           {
521             int i = ReadInteger ();
522
523             val = i;
524             key = MSymbol.integer;
525           }
526         else if (c == '-')
527           {
528             Read ();
529             c = Peek ();
530             if (c >= '0' && c <= '9')
531               {
532                 int i = ReadInteger ();
533                 val = - i;
534                 key = MSymbol.integer;
535               }
536             else
537               {
538                 string str = ReadSymbolName ();
539
540                 val = MSymbol.Of ("-" + str);
541                 key = MSymbol.symbol;
542               }
543           }
544         else if (c == '?')
545           {
546             Read ();
547             val = ReadChar ();
548             key = MSymbol.integer;
549           }
550         else if (c == '#')
551           {
552             Read ();
553             if ((c = Peek ()) == 'x' || c == 'u')
554               {
555                 Read ();
556                 val = ReadHexadecimal ();
557                 key = MSymbol.integer;
558               }
559             else
560               {
561                 val = MSymbol.Of ("#" + (char) c + ReadSymbolName ());
562                 key = MSymbol.symbol;
563               }
564           }
565         else if (c == -1 || c == ')')
566           {
567             if (c == ')')
568               Read ();
569             val = null;
570             key = MSymbol.nil;
571             return false;
572           }
573         else
574           {
575             val = MSymbol.Of (ReadSymbolName ());
576             key = MSymbol.symbol;
577           }
578         return true;
579       }
580     }
581   }
582 }