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