*** empty log message ***
[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 (MStreamReader reader)
22       {
23         MSymbol key;
24         object val;
25         bool result = reader.ReadElement (out key, out val);
26
27         Key = key;
28         Val = val;
29         if (result)
30           next = new MPlist (reader);
31       }
32
33     public MPlist (MStreamReader reader, int count)
34       {
35         MSymbol key;
36         object val;
37         bool result = reader.ReadElement (out key, out val);
38
39         Key = key;
40         Val = val;
41         if (result && --count > 0)
42           next = new MPlist (reader, count);
43         else
44           next = new MPlist ();
45       }
46
47     public MPlist (MStreamReader reader, MSymbol target, MSymbol stop)
48       {
49         MSymbol key;
50         object val;
51         bool result;
52
53         Key = MSymbol.nil;
54         Val = null;
55         while (true)
56           {
57             result = reader.ReadElement (out key, out val);
58             if (! result)
59               return;
60             if (key == MSymbol.plist)
61               {
62                 MPlist plist = (MPlist) val;
63
64                 if (plist.IsSymbol)
65                   {
66                     if (plist.Symbol == stop)
67                       return;
68                     if (plist.Symbol == target)
69                       {
70                         Key = target;
71                         Val = val;
72                         next = new MPlist ();
73                         return;
74                       }
75                   }
76               }
77           }
78       }
79
80     private MPlist (MSymbol key, object val)
81       {
82         Key = key;
83         Val = val;
84       }
85
86     public bool IsEmpty { get { return next == null; } }
87     public MPlist Next { get { return next; } }
88
89     internal bool IsSymbol { get { return Key == MSymbol.symbol; } }
90     internal bool IsMText { get { return Key == MSymbol.mtext; } }
91     internal bool IsPlist { get { return Key == MSymbol.plist; } }
92     internal bool IsInteger { get { return Key == MSymbol.integer; } }
93
94     internal MSymbol Symbol { get { return (MSymbol) Val; } }
95     internal MText Text { get { return (MText) Val; } }
96     internal MPlist Plist { get { return (MPlist) Val; } }
97     internal int Integer { get { return (int) Val; } }
98
99     public int Count
100     {
101       get
102         {
103           int i = 0;
104
105           for (MPlist p = this; p.next != null; i++, p = p.next);
106           return i;
107         }
108     }
109
110     public MPlist Clone ()
111     {
112       MPlist plist = new MPlist (), pl = plist;
113
114       for (MPlist p = this; p.next != null; p = p.next)
115         pl = pl.Add (p.Key, p.Val);
116       return plist;
117     }
118
119     public override string ToString ()
120     {
121         string str = "(";
122
123         for (MPlist p = this; ! p.IsEmpty; p = p.next)
124           {
125             if (p != this)
126               str += " ";
127             if (p.Key != MSymbol.symbol
128                 && p.Key != MSymbol.integer
129                 && p.Key != MSymbol.plist
130                 && p.Key != MSymbol.mtext)
131               str += p.Key + ":";
132             if (p.Key == MSymbol.mtext)
133               str += "\"" + p.Val + "\"";
134             else
135               str += p.Val;
136           }
137         return str + ")";
138     }
139
140     private MPlist find (MSymbol key)
141     {
142       MPlist p;
143
144       for (p = this; ! p.IsEmpty; p = p.next)
145         if (p.Key == key)
146           break;
147       return p;
148     }
149
150     public MPlist Find (MSymbol key)
151     {
152       MPlist p = find (key);
153
154       return (p.IsEmpty ? null : p);
155     }
156
157     public object Get (MSymbol key)
158     {
159       return find (key).Val;
160     }
161
162     internal MPlist Assq (MSymbol key)
163     {
164       foreach (MPlist p in this)
165         if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key)
166           return p;
167       return null;
168     }
169
170     private delegate MPlist MPlistDelegate (MSymbol key, object val);
171
172     private MPlist mplist_op (MPlistDelegate op, object val)
173     {
174       Type type = val.GetType ();
175
176       if (Object.ReferenceEquals (type, typeof (MSymbol)))
177         return op (MSymbol.symbol, val);
178       if (Object.ReferenceEquals (type, typeof (MText)))
179         return op (MSymbol.mtext, val);
180       if (Object.ReferenceEquals (type, typeof (MPlist)))
181         return op (MSymbol.plist, val);
182       if (Object.ReferenceEquals (type, typeof (int)))
183         return op (MSymbol.integer, val);
184       return op (MSymbol.t, val);
185     }
186
187     public MPlist Set (MSymbol key, object val)
188     {
189       if (IsEmpty)
190         Push (key, val);
191       else
192         Val = val;
193       return this;
194     }
195
196     public MPlist Set (object val)
197     {
198       return mplist_op (Set, val);
199     }
200
201     public MPlist Put (MSymbol key, object val)
202     {
203       return find (key).Set (key, val);
204     }
205
206     public MPlist Put (object val)
207     {
208       return mplist_op (Put, val);
209     }
210
211     public MPlist Push (MSymbol key, object val)
212     {
213       MPlist p = new MPlist (Key, Val);
214
215       p.next = this.next;
216       Key = key;
217       Val = val;
218       next = p;
219       return this;
220     }
221
222     public MPlist Push (object val)
223     {
224       return mplist_op (Push, val);
225     }
226
227     public object Pop (out MSymbol key)
228     {
229       key = Key;
230       if (IsEmpty)
231         return null;
232
233       object val = Val;
234
235       Key = next.Key;
236       Val = next.Val;
237       next = next.next;
238       return val;
239     }
240
241     public object Pop ()
242     {
243       MSymbol key;
244       return Pop (out key);
245     }
246
247     public MPlist Add (MSymbol key, object val)
248     {
249       MPlist p;
250
251       for (p = this; ! p.IsEmpty; p = p.next);
252       return p.Push (key, val);
253     }
254
255     public MPlist Clear ()
256     {
257       Key = MSymbol.nil;
258       Val = null;
259       next = null;
260       return this;
261     }
262
263     // Implement IEnumerable interface.
264     //   foreach (MPlist p in plist) { ... }
265
266     public virtual IEnumerator GetEnumerator ()
267     {
268       return new Enumerator (this);
269     }
270
271     private class Enumerator : IEnumerator
272     {
273       private MPlist plist;
274       private MPlist current;
275
276       internal Enumerator (MPlist plist)
277         {
278           this.plist = plist;
279         }
280
281       public object Current
282       {
283         get {
284           if (current == null || current.IsEmpty)
285             throw new InvalidOperationException ();
286           return current;
287         }
288       }
289
290       public void Reset ()
291       {
292         current = null;
293       }
294
295       public bool MoveNext ()
296       {
297         if (current == null)
298           current = plist;
299         else
300           current = current.next;
301         return (! current.IsEmpty);
302       }
303     }
304   }
305
306   public class MStreamReader : StreamReader
307   {
308     private static char[] escaped_char = new char[128];
309     private static int[] hexadecimal = new int[128];
310
311     public MStreamReader (Stream stream) : base (stream)
312       {
313       }
314
315     static MStreamReader ()
316       {
317         for (int i = 0; i < 128; i++)
318           escaped_char[i] = (char) i;
319         escaped_char['e'] = (char) 27;
320         escaped_char['b'] = '\b';
321         escaped_char['f'] = '\f';
322         escaped_char['n'] = '\n';
323         escaped_char['r'] = '\r';
324         escaped_char['t'] = '\t';
325         escaped_char['\\'] = '\\';
326         for (int i = 0; i < 128; i++)
327           hexadecimal[i] = -1;
328         for (int i = '0'; i <= '9'; i++)
329           hexadecimal[i] = i - '0';
330         for (int i = 'A'; i <= 'F'; i++)
331           hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
332       }
333
334     internal int PeekChar ()
335     {
336       bool comment = false;
337       int c;
338
339       while ((c = Peek ()) != -1)
340         {
341           if (comment)
342             {
343               if ((c = Read ()) == '\n')
344                 comment = false;
345             }
346           else
347             {
348               if (c == ';')
349                 comment = true;
350               else if (c != ' ' && c != '\t' && c != '\n')
351                 return c;
352               Read ();
353             }
354         }
355       return c;
356     }
357
358     internal int ReadHexadecimal ()
359     {
360       int i = 0, c;
361
362       while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
363         {
364           Read ();
365           i = (i * 16) + c;
366         }
367       return i;
368     }
369
370     internal int ReadInteger ()
371     {
372       int i = 0, c;
373
374       while ((c = Peek ()) >= '0' && c <= '9')
375         i = (i * 10) + (Read () - '0');
376       return i;
377     }
378
379     internal int ReadChar ()
380     {
381       int c = Read ();
382
383       if (c == '\\')
384         {
385           c = Read ();
386           if (c == -1)
387             return -1;
388           if (c == 'x' || c == 'u')
389             return ReadHexadecimal ();
390           if (c < 128)
391             c = escaped_char[c];
392         }
393       return c;
394     }
395
396     internal MText ReadMtext ()
397     {
398       MText mt = new MText ();
399       int c;
400
401       while ((c = Peek ()) != -1 && c != '"')
402         {
403           if (c == '\\')
404             {
405               c = ReadChar ();
406               if (Peek () == '\n')
407                 {
408                   ReadChar ();
409                   continue;
410                 }
411               if (c == -1)
412                 {
413                   mt.Cat ('\\');
414                   break;
415                 }
416               mt.Cat (c);
417             }
418           else
419             mt.Cat (Read ());
420         }
421       if (c == '"')
422         Read ();
423       return mt;
424     }
425
426     internal string ReadSymbolName ()
427     {
428       int c = Peek ();
429
430       if (c == -1 || c == '(' || c == ')' || c == ' ' || c == '\n' || c == '"')
431         return "";
432       Read ();
433       if (c == '\\')
434         {
435           c = Read ();
436           if (c == -1)
437             c = '\\';
438         }
439       return (char) c + ReadSymbolName ();
440     }
441
442     internal bool ReadElement (out MSymbol key, out object val)
443     {
444       int c = PeekChar ();
445
446       if (c == '(')
447         {
448           Read ();
449           val = new MPlist (this);
450           key = MSymbol.plist;
451         }
452       else if (c == '"')
453         {
454           Read ();
455           val = ReadMtext ();
456           key = MSymbol.mtext;
457         }
458       else if (c >= '0' && c <= '9')
459         {
460           int i = ReadInteger ();
461
462           val = i;
463           key = MSymbol.integer;
464         }
465       else if (c == '-')
466         {
467           Read ();
468           c = Peek ();
469           if (c >= '0' && c <= '9')
470             {
471               int i = ReadInteger ();
472               val = - i;
473               key = MSymbol.integer;
474             }
475           else
476             {
477               string str = ReadSymbolName ();
478
479               val = MSymbol.Of ("-" + str);
480               key = MSymbol.symbol;
481             }
482         }
483       else if (c == '?')
484         {
485           Read ();
486           val = ReadChar ();
487           key = MSymbol.integer;
488         }
489       else if (c == '#')
490         {
491           Read ();
492           if ((c = Peek ()) == 'x' || c == 'u')
493             {
494               Read ();
495               val = ReadHexadecimal ();
496               key = MSymbol.integer;
497             }
498           else
499             {
500               string str = ReadSymbolName ();
501
502               val = MSymbol.Of ("#" + (char) c + str);
503               key = MSymbol.symbol;
504             }
505         }
506       else if (c == -1 || c == ')')
507         {
508           if (c == ')')
509             Read ();
510           val = null;
511           key = MSymbol.nil;
512           return false;
513         }
514       else
515         {
516           val = MSymbol.Of (ReadSymbolName ());
517           key = MSymbol.symbol;
518         }
519       return true;
520     }
521   }
522 }