f54b47f561d2ce1a2d3b491d744e2e2318c96be8
[m17n/m17n-lib-cs.git] / MPlist.cs
1 using System;
2 using System.Collections;
3 using M17N.Core;
4
5 namespace M17N.Core
6 {
7   public struct MProperty
8   {
9     internal MSymbol key;
10     internal object val;
11
12     public MSymbol Key { get { return this.key;} }
13     public object Val { get { return this.val; } }
14
15     public MProperty (MSymbol key, object val)
16       {
17         this.key = key;
18         this.val = val;
19       }
20   }
21
22   public class MPlist : IEnumerable
23   {
24     private MProperty prop;
25     private MPlist next;
26
27     public MPlist ()
28     {
29       prop = new MProperty (MSymbol.nil, null);
30     }
31
32     public bool tailp { get { return prop.key == MSymbol.nil; } }
33
34     public new string ToString ()
35     {
36       string str = "";
37
38       for (MPlist p = this; ! p.tailp; p = p.next)
39         {
40           str += (p == this ? "(" : " ") + p.prop.key.ToString () + ":";
41           if (p.prop.val is MSymbol)
42             str += ((MSymbol) p.prop.val).ToString ();
43           else if (p.prop.val is MPlist)
44             str += ((MPlist) p.prop.val).ToString ();
45         }
46       return str + ")";
47     }
48
49     public object get (MSymbol key)
50     {
51       if ((object) key == null)
52         return null;
53       for (MPlist p = this; ! p.tailp; p = p.next)
54         if (p.prop.key == key)
55           return p.prop.val;
56       return null;
57     }
58
59     public object put (MSymbol key, object val)
60     {
61       MPlist p;
62
63       for (p = this; ! p.tailp; p = p.next)
64         if (p.prop.key == key)
65           {
66             if (val != null)
67               p.prop.val = val;
68             else
69               p.pop ();
70             return val;
71           }
72       if (val != null)
73         {
74           p.prop.key = key;
75           p.prop.val = val;
76           p.next = new MPlist ();
77         }
78       return val;
79     }
80
81     public object push (MSymbol key, object val)
82     {
83       MPlist p = new MPlist ();
84
85       p.prop.key = this.prop.key;
86       p.prop.val = this.prop.val;
87       p.next = this.next;
88       this.prop.key = key;
89       this.prop.val = val;
90       this.next = p;
91
92       return val;
93     }
94
95     public object pop ()
96     {
97       if (tailp)
98         return null;
99
100       object val = this.prop.val;
101
102       this.prop.key = this.next.prop.key;
103       this.prop.val = this.next.prop.val;
104       this.next = this.next.next;
105       return val;
106     }
107
108     public object add (MSymbol key, object val)
109     {
110       MPlist p;
111
112       for (p = this; ! p.tailp; p = p.next);
113       if (val != null)
114         {
115           p.prop.key = key;
116           p.prop.val = val;
117           p.next = new MPlist ();
118         }
119       return val;
120     }
121
122     public MPlist find (MSymbol key)
123     {
124       for (MPlist p = this; ! p.tailp; p = p.next)
125         if (p.prop.key == key)
126           return p;
127       return null;
128     }
129
130     // Implement IEnumerable interface.
131
132     public virtual IEnumerator GetEnumerator ()
133     {
134       return new Enumerator (this);
135     }
136
137     private class Enumerator : IEnumerator
138     {
139       private MPlist plist;
140       private MPlist current;
141
142       internal Enumerator (MPlist plist)
143         {
144           this.plist = plist;
145         }
146
147       public object Current
148       {
149         get {
150           if (current == null || current.tailp)
151             throw new InvalidOperationException ();
152           return current;
153         }
154       }
155
156       public void Reset ()
157       {
158         current = null;
159       }
160
161       public bool MoveNext ()
162       {
163         if (current == null)
164           current = plist;
165         else if (current.tailp)
166           return false;
167         else
168           current = current.next;
169         return true;
170       }
171     }
172   }
173 }