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