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