*** 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         {
328           this.key = key;
329           this.val = val;
330         }
331       return this;
332     }
333
334     public MPlist Set (object val)
335     {
336       return mplist_op (Set, val);
337     }
338
339     public MPlist Put (MSymbol key, object val)
340     {
341       return find (key).Set (key, val);
342     }
343
344     public MPlist Put (object val)
345     {
346       return mplist_op (Put, val);
347     }
348
349     public MPlist Push (MSymbol key, object val)
350     {
351       MPlist p = new MPlist (this.key, this.val);
352
353       p.next = this.next;
354       this.key = key;
355       this.val = val;
356       next = p;
357       return this;
358     }
359
360     public MPlist Push (object val)
361     {
362       return mplist_op (Push, val);
363     }
364
365     public object Pop (out MSymbol key)
366     {
367       key = this.key;
368       if (IsEmpty)
369         return null;
370
371       object this_val = val;
372
373       this.key = next.key;
374       this.val = next.val;
375       next = next.next;
376       return this_val;
377     }
378
379     public object Pop ()
380     {
381       MSymbol temp;
382       return Pop (out temp);
383     }
384
385     public MPlist Add (MSymbol key, object val)
386     {
387       MPlist p;
388
389       for (p = this; ! p.IsEmpty; p = p.next);
390       return p.Push (key, val);
391     }
392
393     public MPlist Cons (MSymbol key, object val)
394     {
395       MPlist plist = new MPlist ();
396       plist.key = key;
397       plist.val = val;
398       plist.next = this;
399       return plist;
400     }
401
402     public MPlist Clear ()
403     {
404       key = MSymbol.nil;
405       val = null;
406       next = null;
407       return this;
408     }
409
410     // Implement IEnumerable interface.
411     //   foreach (MPlist p in plist) { ... }
412
413     public virtual IEnumerator GetEnumerator ()
414     {
415       return new Enumerator (this);
416     }
417
418     private class Enumerator : IEnumerator
419     {
420       private MPlist plist;
421       private MPlist current;
422
423       internal Enumerator (MPlist plist)
424         {
425           this.plist = plist;
426         }
427
428       public object Current
429       {
430         get {
431           if (current == null || current.IsEmpty)
432             throw new InvalidOperationException ();
433           return current;
434         }
435       }
436
437       public void Reset ()
438       {
439         current = null;
440       }
441
442       public bool MoveNext ()
443       {
444         if (current == null)
445           current = plist;
446         else
447           current = current.next;
448         return (! current.IsEmpty);
449       }
450     }
451   }
452
453   public class MStreamReader : StreamReader
454   {
455     private static char[] escaped_char = new char[128];
456     private static int[] hexadecimal = new int[128];
457     private char comment_start;
458     private bool line_oriented;
459
460     public MStreamReader (Stream stream) : base (stream)
461       {
462         comment_start = ';';
463         line_oriented = false;
464       }
465
466     public MStreamReader (Stream stream, char comment_start,
467                           bool line_oriented) : base (stream)
468       {
469         this.comment_start = comment_start;
470         this.line_oriented = line_oriented;
471       }
472
473     static MStreamReader ()
474       {
475         for (int i = 0; i < 128; i++)
476           escaped_char[i] = (char) i;
477         escaped_char['0'] = (char) 0;
478         escaped_char['e'] = (char) 27;
479         escaped_char['a'] = '\a';
480         escaped_char['b'] = '\b';
481         escaped_char['f'] = '\f';
482         escaped_char['n'] = '\n';
483         escaped_char['r'] = '\r';
484         escaped_char['t'] = '\t';
485         escaped_char['v'] = '\v';
486         for (int i = 0; i < 128; i++)
487           hexadecimal[i] = -1;
488         for (int i = '0'; i <= '9'; i++)
489           hexadecimal[i] = i - '0';
490         for (int i = 'A'; i <= 'F'; i++)
491           hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
492       }
493
494     private int ReadHexadecimal (int max)
495     {
496       int i = 0, c;
497
498       while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
499         {
500           if (max >= 0 && (i * 16) + c >= max)
501             break;
502           Read ();
503           i = (i * 16) + c;
504         }
505       return i;
506     }
507
508     public bool ForwardLine ()
509     {
510       int c;
511       while ((c = Read ()) >=0 && c != '\n');
512       return (c == '\n');
513     }
514
515     public bool SkipSpace (out int c)
516     {
517       while ((c = Peek ()) == ' ' && c == '\t' && c == '\f')
518         Read ();
519       return (c >= 0);
520     }
521
522     public bool PeekChar (out int c)
523     {
524       while ((c = Peek ()) != -1)
525         {
526           if (c == comment_start)
527             ForwardLine ();
528           else if (c != ' ' && c != '\t' && c != '\n')
529             return true;
530           else if (c == '\n' && line_oriented)
531             return false;
532           else
533             Read ();
534         }
535       return false;
536     }
537
538     public bool ReadInteger (out int i)
539     {
540       int c = Peek ();
541
542       i = 0;
543       if (c < 0)
544         return false;
545       if (c == '0')
546         {
547           Read ();
548           c = Peek ();
549           if (c == 'x')
550             {
551               Read ();
552               i = ReadHexadecimal (-1);
553               return true;
554             }
555         }
556       while ((c = Peek ()) >= '0' && c <= '9')
557         i = (i * 10) + (Read () - '0');
558       return true;
559     }
560
561     public bool ReadChar (out int c)
562     {
563       c = Read ();
564       if (c < 0 || (line_oriented && c == '\n'))
565         return false;
566       if (c == '\\')
567         {
568           c = Read ();
569           if (c == '\n')
570             return ReadChar (out c);
571           if (c < 0)
572             c = '\\';
573           else if (c == 'x' || c == 'u' || c == 'U')
574             c = ReadHexadecimal (0x10FFFF);
575           else if (c < 128)
576             c = escaped_char[c];
577         }
578       return true;
579     }
580
581     private bool read_string (out string str, int prefix, bool for_symbol)
582     {
583       char[] buf = new char[256];
584       int c;
585       int i = 0;
586
587       str = null;
588       if (prefix >= 0)
589         buf[i++] = (char) prefix;
590       while ((c = Peek ()) >= 0
591              && c != '\"'
592              && (! for_symbol
593                  || (c != '(' && c != ')' && c != ' ' && c != '\t' && c != '\n')))
594         {
595           if (! ReadChar (out c))
596             break;
597           if (c < 0x10000)
598             {
599               buf[i++] = (char) c;
600             }
601           else
602             {
603               buf[i++] = (char) (0xD800 + ((c - 0x10000) >> 10));
604               buf[i++] = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
605             }
606           if (i >= 255)
607             {
608               if (str == null)
609                 str = new string (buf, 0, i);
610               else
611                 str += new string (buf, 0, i);
612               i = 0;
613             }
614         }
615       if (c == '\"' && ! for_symbol)
616         Read ();
617       if (i > 0)
618         {
619           if (str == null)
620             str = new string (buf, 0, i);
621           else
622             str += new string (buf, 0, i);
623         }
624       return (str != null);
625     }
626
627     public bool ReadString (out string str)
628     {
629       return read_string (out str, -1, false);
630     }
631
632     public bool ReadMText (out MText mt)
633     {
634       int c = Peek ();
635
636       if (c == '"')
637         {
638           string str;
639
640           Read ();
641           if (read_string (out str, -1, false))
642             mt = new MText (str);
643           else
644             mt = new MText ();
645           return true;
646         }
647       mt = new MText ();
648       if (c == '\\')
649         {
650           while ((c = Peek ()) == '\\')
651             {
652               Read ();
653               c = Peek ();
654               if (c != 'x')
655                 break;
656               Read ();
657               mt.Cat (ReadHexadecimal (0x10FFFF));
658             }
659           return true;
660         }
661       return false;
662     }
663
664     public bool ReadSymbol (out MSymbol sym, int prefix)
665     {
666       string str;
667
668       if (read_string (out str, prefix, true))
669         {
670           sym = MSymbol.Of (str);
671           return true;
672         }
673       sym = MSymbol.nil;
674       return false;
675     }
676
677     internal bool ReadElement (out MSymbol key, out object val)
678     {
679       int c;
680
681       if (! PeekChar (out c))
682         {
683           val = null;
684           key = MSymbol.nil;
685           return false;
686         }
687
688       if (c == '(')
689         {
690           Read ();
691           val = new MPlist (this);
692           key = MSymbol.plist;
693         }
694       else if (c == '"')
695         {
696           MText mt;
697           ReadMText (out mt);
698           val = mt;
699           key = MSymbol.mtext;
700         }
701       else if (c >= '0' && c <= '9')
702         {
703           int i;
704           ReadInteger (out i);
705           val = i;
706           key = MSymbol.integer;
707         }
708       else if (c == '-')
709         {
710           Read ();
711           c = Peek ();
712           if (c >= '0' && c <= '9')
713             {
714               int i;
715               ReadInteger (out i);
716               val = - i;
717               key = MSymbol.integer;
718             }
719           else
720             {
721               MSymbol sym;
722
723               ReadSymbol (out sym, '-');
724               val = sym;
725               key = MSymbol.symbol;
726             }
727         }
728       else if (c == '?')
729         {
730           Read ();
731           if (ReadChar (out c))
732             {
733               val = c;
734               key = MSymbol.integer;
735             }
736           else
737             {
738               val = null;
739               key = MSymbol.nil;
740             }
741         }
742       else if (c == '#')
743         {
744           Read ();
745           if ((c = Peek ()) == 'x' || c == 'u')
746             {
747               Read ();
748               val = ReadHexadecimal (-1);
749               key = MSymbol.integer;
750             }
751           else
752             {
753               MSymbol sym;
754
755               ReadSymbol (out sym, '#');
756               val = sym;
757               key = MSymbol.symbol;
758             }
759         }
760       else if (c == ')')
761         {
762           Read ();
763           val = null;
764           key = MSymbol.nil;
765           return false;
766         }
767       else
768         {
769           MSymbol sym;
770
771           ReadSymbol (out sym, -1);
772           val = sym;
773           key = MSymbol.symbol;
774         }
775       return true;
776     }
777   }
778 }