*** empty log message ***
[m17n/m17n-lib-cs.git] / MPlist.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 using M17N;
6 using M17N.Core;
7
8 namespace M17N.Core
9 {
10   public class MPlist : IEnumerable
11   {
12     public MSymbol key;
13     public object val;
14     public MPlist next;
15
16     public MSymbol Key { get { return key; } }
17     public object Val { get { return val; } }
18     public MPlist Next { get { return next; } }
19
20     private static List<MSymbol> wf_keys;
21
22     static MPlist ()
23       {
24         wf_keys = new List<MSymbol> ();
25         wf_keys.Add (MSymbol.symbol);
26         wf_keys.Add (MSymbol.mtext);
27         wf_keys.Add (MSymbol.plist);
28         wf_keys.Add (MSymbol.integer);
29       }
30
31     public MPlist ()
32       {
33         key = MSymbol.nil;
34         val = null;
35       }
36
37     public MPlist (FileStream stream)
38       {
39         MStreamReader reader = new MStreamReader (stream);
40         bool result = reader.ReadElement (out key, out val);
41
42         if (result)
43           next = new MPlist (reader);
44       }
45
46     public MPlist (FileStream stream, int count)
47       {
48         MStreamReader reader = new MStreamReader (stream);
49         bool result = reader.ReadElement (out key, out val);
50
51         if (result && --count > 0)
52           next = new MPlist (reader, count);
53         else
54           next = new MPlist ();
55       }
56
57     public MPlist (FileStream stream, MSymbol stop)
58       {
59         MStreamReader reader = new MStreamReader (stream);
60         bool result;
61
62         key = MSymbol.nil;
63         val = null;
64         while (true)
65           {
66             MSymbol this_key;
67             object this_val;
68
69             result = reader.ReadElement (out this_key, out this_val);
70             if (! result)
71               return;
72             if (this_key == MSymbol.plist)
73               {
74                 MPlist plist = (MPlist) this_val;
75
76                 if (plist.IsSymbol && plist.Symbol == stop)
77                   return;
78               }
79             key = this_key;
80             val = this_val;
81             next = new MPlist (reader, stop);
82           }
83       }
84
85     public MPlist (FileStream stream, MSymbol target, MSymbol stop)
86       {
87         MStreamReader reader = new MStreamReader (stream);
88         bool result;
89
90         key = MSymbol.nil;
91         val = null;
92         while (true)
93           {
94             MSymbol this_key;
95             object this_val;
96
97             result = reader.ReadElement (out this_key, out this_val);
98             if (! result)
99               return;
100             if (this_key == MSymbol.plist)
101               {
102                 MPlist plist = (MPlist) this_val;
103
104                 if (plist.IsSymbol)
105                   {
106                     if (plist.Symbol == stop)
107                       return;
108                     if (plist.Symbol == target)
109                       {
110                         key = target;
111                         val = this_val;
112                         next = new MPlist ();
113                         return;
114                       }
115                   }
116               }
117           }
118       }
119
120     internal MPlist (MStreamReader reader)
121       {
122         bool result = reader.ReadElement (out key, out val);
123
124         if (result)
125           next = new MPlist (reader);
126       }
127
128     private MPlist (MStreamReader reader, int count)
129       {
130         bool result = reader.ReadElement (out key, out val);
131
132         if (result && --count > 0)
133           next = new MPlist (reader, count);
134         else
135           next = new MPlist ();
136       }
137
138     private MPlist (MStreamReader reader, MSymbol stop)
139       {
140         bool result;
141         MPlist next_plist = null;
142
143         key = MSymbol.nil;
144         val = null;
145         while (true)
146           {
147             MSymbol this_key;
148             object this_val;
149
150             result = reader.ReadElement (out this_key, out this_val);
151             if (! result)
152               return;
153             if (this_key == MSymbol.plist)
154               {
155                 MPlist plist = (MPlist) this_val;
156
157                 if (plist.IsSymbol && plist.Symbol == stop)
158                   return;
159               }
160             if (next_plist == null)
161               {
162                 key = this_key;
163                 val = this_val;
164                 next = next_plist = new MPlist ();
165               }
166             else
167               {
168                 next_plist.key = this_key;
169                 next_plist.val = this_val;
170                 next_plist.next = new MPlist ();
171                 next_plist = next_plist.next;
172               }
173           }
174       }
175
176     private MPlist (MStreamReader reader, MSymbol target, MSymbol stop)
177       {
178         bool result;
179
180         key = MSymbol.nil;
181         val = null;
182         while (true)
183           {
184             MSymbol this_key;
185             object this_val;
186
187             result = reader.ReadElement (out this_key, out this_val);
188             if (! result)
189               return;
190             if (this_key == MSymbol.plist)
191               {
192                 MPlist plist = (MPlist) this_val;
193
194                 if (plist.IsSymbol)
195                   {
196                     if (plist.Symbol == stop)
197                       return;
198                     if (plist.Symbol == target)
199                       {
200                         key = target;
201                         val = this_val;
202                         next = new MPlist ();
203                         return;
204                       }
205                   }
206               }
207           }
208       }
209
210     protected MPlist (MSymbol key, object val)
211       {
212         this.key = key;
213         this.val = val;
214       }
215
216     public bool IsEmpty { get { return next == null; } }
217
218     public bool IsSymbol { get { return Key == MSymbol.symbol; } }
219     public bool IsMText { get { return Key == MSymbol.mtext; } }
220     public bool IsPlist { get { return Key == MSymbol.plist; } }
221     public bool IsInteger { get { return Key == MSymbol.integer; } }
222
223     public MSymbol Symbol { get { return (MSymbol) val; } }
224     public MText Text { get { return (MText) val; } }
225     public MPlist Plist { get { return (MPlist) val; } }
226     public int Integer { get { return (int) val; } }
227
228     public int Count
229     {
230       get
231         {
232           int i = 0;
233
234           for (MPlist p = this; p.next != null; i++, p = p.next);
235           return i;
236         }
237     }
238
239     public MPlist this[int i]
240     {
241       get {
242         MPlist p;
243         for (p = this; ! p.IsEmpty && i > 0; i--, p = p.next);
244         return (i == 0 ? p : null);
245       }
246     }
247
248     public MPlist Clone ()
249     {
250       MPlist plist = new MPlist (), pl = plist;
251
252       for (MPlist p = this; p.next != null; p = p.next)
253         pl = pl.Add (p.key, p.val);
254       return plist;
255     }
256
257     public override string ToString ()
258     {
259         string str = "(";
260
261         for (MPlist p = this; ! p.IsEmpty; p = p.next)
262           {
263             if (p != this)
264               str += " ";
265             if (! wf_keys.Contains (p.key))
266               str += p.key + ":";
267             if (p.key == MSymbol.mtext)
268               str += "\"" + p.val + "\"";
269             else
270               str += p.val;
271           }
272         return str + ")";
273     }
274
275     private MPlist find (MSymbol key)
276     {
277       MPlist p;
278
279       for (p = this; ! p.IsEmpty; p = p.next)
280         if (p.key == key)
281           break;
282       return p;
283     }
284
285     public MPlist Find (MSymbol key)
286     {
287       MPlist p = find (key);
288
289       return (p.IsEmpty ? null : p);
290     }
291
292     public object Get (MSymbol key)
293     {
294       return find (key).val;
295     }
296
297     internal MPlist Assq (MSymbol key)
298     {
299       foreach (MPlist p in this)
300         if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key)
301           return p;
302       return null;
303     }
304
305     private delegate MPlist MPlistDelegate (MSymbol key, object val);
306
307     private MPlist mplist_op (MPlistDelegate op, object val)
308     {
309       Type type = val.GetType ();
310
311       if (Object.ReferenceEquals (type, typeof (MSymbol)))
312         return op (MSymbol.symbol, val);
313       if (Object.ReferenceEquals (type, typeof (MText)))
314         return op (MSymbol.mtext, val);
315       if (Object.ReferenceEquals (type, typeof (MPlist)))
316         return op (MSymbol.plist, val);
317       if (Object.ReferenceEquals (type, typeof (int)))
318         return op (MSymbol.integer, val);
319       return op (MSymbol.t, val);
320     }
321
322     public MPlist Set (MSymbol key, object val)
323     {
324       if (IsEmpty)
325         Push (key, val);
326       else
327         this.val = val;
328       return this;
329     }
330
331     public MPlist Set (object val)
332     {
333       return mplist_op (Set, val);
334     }
335
336     public MPlist Put (MSymbol key, object val)
337     {
338       return find (key).Set (key, val);
339     }
340
341     public MPlist Put (object val)
342     {
343       return mplist_op (Put, val);
344     }
345
346     public MPlist Push (MSymbol key, object val)
347     {
348       MPlist p = new MPlist (this.key, this.val);
349
350       p.next = this.next;
351       this.key = key;
352       this.val = val;
353       next = p;
354       return this;
355     }
356
357     public MPlist Push (object val)
358     {
359       return mplist_op (Push, val);
360     }
361
362     public object Pop (out MSymbol key)
363     {
364       key = this.key;
365       if (IsEmpty)
366         return null;
367
368       object this_val = val;
369
370       this.key = next.key;
371       this.val = next.val;
372       next = next.next;
373       return this_val;
374     }
375
376     public object Pop ()
377     {
378       MSymbol temp;
379       return Pop (out temp);
380     }
381
382     public MPlist Add (MSymbol key, object val)
383     {
384       MPlist p;
385
386       for (p = this; ! p.IsEmpty; p = p.next);
387       return p.Push (key, val);
388     }
389
390     public MPlist Cons (MSymbol key, object val)
391     {
392       MPlist plist = new MPlist ();
393       plist.key = key;
394       plist.val = val;
395       plist.next = this;
396       return plist;
397     }
398
399     public MPlist Clear ()
400     {
401       key = MSymbol.nil;
402       val = null;
403       next = null;
404       return this;
405     }
406
407     // Implement IEnumerable interface.
408     //   foreach (MPlist p in plist) { ... }
409
410     public virtual IEnumerator GetEnumerator ()
411     {
412       return new Enumerator (this);
413     }
414
415     private class Enumerator : IEnumerator
416     {
417       private MPlist plist;
418       private MPlist current;
419
420       internal Enumerator (MPlist plist)
421         {
422           this.plist = plist;
423         }
424
425       public object Current
426       {
427         get {
428           if (current == null || current.IsEmpty)
429             throw new InvalidOperationException ();
430           return current;
431         }
432       }
433
434       public void Reset ()
435       {
436         current = null;
437       }
438
439       public bool MoveNext ()
440       {
441         if (current == null)
442           current = plist;
443         else
444           current = current.next;
445         return (! current.IsEmpty);
446       }
447     }
448   }
449
450   public class MStreamReader : StreamReader
451   {
452     private static char[] escaped_char = new char[128];
453     private static int[] hexadecimal = new int[128];
454     private char comment_start;
455     private bool line_oriented;
456
457     public MStreamReader (Stream stream) : base (stream)
458       {
459         comment_start = ';';
460         line_oriented = false;
461       }
462
463     public MStreamReader (Stream stream, char comment_start,
464                           bool line_oriented) : base (stream)
465       {
466         this.comment_start = comment_start;
467         this.line_oriented = line_oriented;
468       }
469
470     static MStreamReader ()
471       {
472         for (int i = 0; i < 128; i++)
473           escaped_char[i] = (char) i;
474         escaped_char['0'] = (char) 0;
475         escaped_char['e'] = (char) 27;
476         escaped_char['a'] = '\a';
477         escaped_char['b'] = '\b';
478         escaped_char['f'] = '\f';
479         escaped_char['n'] = '\n';
480         escaped_char['r'] = '\r';
481         escaped_char['t'] = '\t';
482         escaped_char['v'] = '\v';
483         for (int i = 0; i < 128; i++)
484           hexadecimal[i] = -1;
485         for (int i = '0'; i <= '9'; i++)
486           hexadecimal[i] = i - '0';
487         for (int i = 'A'; i <= 'F'; i++)
488           hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
489       }
490
491     private int ReadHexadecimal (int max)
492     {
493       int i = 0, c;
494
495       while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
496         {
497           if (max >= 0 && (i * 16) + c >= max)
498             break;
499           Read ();
500           i = (i * 16) + c;
501         }
502       return i;
503     }
504
505     public bool ForwardLine ()
506     {
507       int c;
508       while ((c = Read ()) >=0 && c != '\n');
509       return (c == '\n');
510     }
511
512     public bool SkipSpace (out int c)
513     {
514       while ((c = Peek ()) == ' ' && c == '\t' && c == '\f')
515         Read ();
516       return (c >= 0);
517     }
518
519     public bool PeekChar (out int c)
520     {
521       while ((c = Peek ()) != -1)
522         {
523           if (c == comment_start)
524             ForwardLine ();
525           else if (c != ' ' && c != '\t' && c != '\n')
526             return true;
527           else if (c == '\n' && line_oriented)
528             return false;
529           else
530             Read ();
531         }
532       return false;
533     }
534
535     public bool ReadInteger (out int i)
536     {
537       int c = Peek ();
538
539       i = 0;
540       if (c < 0)
541         return false;
542       if (c == '0')
543         {
544           Read ();
545           c = Peek ();
546           if (c == 'x')
547             {
548               Read ();
549               i = ReadHexadecimal (-1);
550               return true;
551             }
552         }
553       while ((c = Peek ()) >= '0' && c <= '9')
554         i = (i * 10) + (Read () - '0');
555       return true;
556     }
557
558     public bool ReadChar (out int c)
559     {
560       c = Read ();
561       if (c < 0 || (line_oriented && c == '\n'))
562         return false;
563       if (c == '\\')
564         {
565           c = Read ();
566           if (c == '\n')
567             return ReadChar (out c);
568           if (c < 0)
569             c = '\\';
570           else if (c == 'x' || c == 'u' || c == 'U')
571             c = ReadHexadecimal (0x10FFFF);
572           else if (c < 128)
573             c = escaped_char[c];
574         }
575       return true;
576     }
577
578     private bool read_string (out string str, int prefix, bool for_symbol)
579     {
580       char[] buf = new char[256];
581       int c;
582       int i = 0;
583
584       str = null;
585       if (prefix >= 0)
586         buf[i++] = (char) prefix;
587       while ((c = Peek ()) >= 0
588              && c != '\"'
589              && (! for_symbol
590                  || (c != '(' && c != ')' && c != ' ' && c != '\t' && c != '\n')))
591         {
592           if (! ReadChar (out c))
593             break;
594           if (c < 0x10000)
595             {
596               buf[i++] = (char) c;
597             }
598           else
599             {
600               buf[i++] = (char) (0xD800 + ((c - 0x10000) >> 10));
601               buf[i++] = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
602             }
603           if (i >= 255)
604             {
605               if (str == null)
606                 str = new string (buf, 0, i);
607               else
608                 str += new string (buf, 0, i);
609               i = 0;
610             }
611         }
612       if (c == '\"' && ! for_symbol)
613         Read ();
614       if (i > 0)
615         {
616           if (str == null)
617             str = new string (buf, 0, i);
618           else
619             str += new string (buf, 0, i);
620         }
621       return (str != null);
622     }
623
624     public bool ReadString (out string str)
625     {
626       return read_string (out str, -1, false);
627     }
628
629     public bool ReadMText (out MText mt)
630     {
631       int c = Peek ();
632
633       if (c == '"')
634         {
635           string str;
636
637           Read ();
638           if (read_string (out str, -1, false))
639             mt = new MText (str);
640           else
641             mt = new MText ();
642           return true;
643         }
644       mt = new MText ();
645       if (c == '\\')
646         {
647           while ((c = Peek ()) == '\\')
648             {
649               Read ();
650               c = Peek ();
651               if (c != 'x')
652                 break;
653               Read ();
654               mt.Cat (ReadHexadecimal (0x10FFFF));
655             }
656           return true;
657         }
658       return false;
659     }
660
661     public bool ReadSymbol (out MSymbol sym, int prefix)
662     {
663       string str;
664
665       if (read_string (out str, prefix, true))
666         {
667           sym = MSymbol.Of (str);
668           return true;
669         }
670       sym = MSymbol.nil;
671       return false;
672     }
673
674     internal bool ReadElement (out MSymbol key, out object val)
675     {
676       int c;
677
678       if (! PeekChar (out c))
679         {
680           val = null;
681           key = MSymbol.nil;
682           return false;
683         }
684
685       if (c == '(')
686         {
687           Read ();
688           val = new MPlist (this);
689           key = MSymbol.plist;
690         }
691       else if (c == '"')
692         {
693           MText mt;
694           ReadMText (out mt);
695           val = mt;
696           key = MSymbol.mtext;
697         }
698       else if (c >= '0' && c <= '9')
699         {
700           int i;
701           ReadInteger (out i);
702           val = i;
703           key = MSymbol.integer;
704         }
705       else if (c == '-')
706         {
707           Read ();
708           c = Peek ();
709           if (c >= '0' && c <= '9')
710             {
711               int i;
712               ReadInteger (out i);
713               val = - i;
714               key = MSymbol.integer;
715             }
716           else
717             {
718               MSymbol sym;
719
720               ReadSymbol (out sym, '-');
721               val = sym;
722               key = MSymbol.symbol;
723             }
724         }
725       else if (c == '?')
726         {
727           Read ();
728           if (ReadChar (out c))
729             {
730               val = c;
731               key = MSymbol.integer;
732             }
733           else
734             {
735               val = null;
736               key = MSymbol.nil;
737             }
738         }
739       else if (c == '#')
740         {
741           Read ();
742           if ((c = Peek ()) == 'x' || c == 'u')
743             {
744               Read ();
745               val = ReadHexadecimal (-1);
746               key = MSymbol.integer;
747             }
748           else
749             {
750               MSymbol sym;
751
752               ReadSymbol (out sym, '#');
753               val = sym;
754               key = MSymbol.symbol;
755             }
756         }
757       else if (c == ')')
758         {
759           Read ();
760           val = null;
761           key = MSymbol.nil;
762           return false;
763         }
764       else
765         {
766           MSymbol sym;
767
768           ReadSymbol (out sym, -1);
769           val = sym;
770           key = MSymbol.symbol;
771         }
772       return true;
773     }
774   }
775 }