*** empty log message ***
[m17n/m17n-lib-cs.git] / MPlist.cs
index ca6022a..27e23e3 100644 (file)
--- a/MPlist.cs
+++ b/MPlist.cs
@@ -1,5 +1,7 @@
 using System;
 using System.Collections;
+using System.IO;
+using M17N;
 using M17N.Core;
 
 namespace M17N.Core
@@ -16,6 +18,18 @@ namespace M17N.Core
        Val = null;
       }
 
+    public MPlist (MStreamReader reader)
+      {
+       MSymbol key;
+       object val;
+       bool result = reader.ReadElement (out key, out val);
+
+       Key = key;
+       Val = val;
+       if (result)
+         next = new MPlist (reader);
+      }
+
     private MPlist (MSymbol key, object val)
       {
        Key = key;
@@ -25,6 +39,16 @@ namespace M17N.Core
     public bool IsEmpty { get { return next == null; } }
     public MPlist Next { get { return next; } }
 
+    internal bool IsSymbol { get { return Key == MSymbol.symbol; } }
+    internal bool IsMText { get { return Key == MSymbol.mtext; } }
+    internal bool IsPlist { get { return Key == MSymbol.plist; } }
+    internal bool IsInteger { get { return Key == MSymbol.integer; } }
+
+    internal MSymbol Symbol { get { return (MSymbol) Val; } }
+    internal MText Text { get { return (MText) Val; } }
+    internal MPlist Plist { get { return (MPlist) Val; } }
+    internal int Integer { get { return (int) Val; } }
+
     public int Count
     {
       get
@@ -47,11 +71,18 @@ namespace M17N.Core
 
     public override string ToString ()
     {
-       string str = "";
+       string str = "(";
 
        for (MPlist p = this; ! p.IsEmpty; p = p.next)
          {
-           str += (p == this ? "(" : " ") + p.Key + ":" + p.Val;
+           if (p != this)
+             str += " ";
+           if (p.Key != MSymbol.symbol
+               && p.Key != MSymbol.integer
+               && p.Key != MSymbol.plist
+               && p.Key != MSymbol.mtext)
+             str += p.Key + ":";
+           str += p.Val;
          }
        return str + ")";
     }
@@ -78,6 +109,23 @@ namespace M17N.Core
       return find (key).Val;
     }
 
+    private delegate MPlist MPlistDelegate (MSymbol key, object val);
+
+    private MPlist mplist_op (MPlistDelegate op, object val)
+    {
+      Type type = val.GetType ();
+
+      if (Object.ReferenceEquals (type, typeof (MSymbol)))
+       return op (MSymbol.symbol, val);
+      if (Object.ReferenceEquals (type, typeof (MText)))
+       return op (MSymbol.mtext, val);
+      if (Object.ReferenceEquals (type, typeof (MPlist)))
+       return op (MSymbol.plist, val);
+      if (Object.ReferenceEquals (type, typeof (int)))
+       return op (MSymbol.integer, val);
+      return op (MSymbol.t, val);
+    }
+
     public MPlist Set (MSymbol key, object val)
     {
       if (IsEmpty)
@@ -87,11 +135,21 @@ namespace M17N.Core
       return this;
     }
 
+    public MPlist Set (object val)
+    {
+      return mplist_op (Set, val);
+    }
+
     public MPlist Put (MSymbol key, object val)
     {
       return find (key).Set (key, val);
     }
 
+    public MPlist Put (object val)
+    {
+      return mplist_op (Put, val);
+    }
+
     public MPlist Push (MSymbol key, object val)
     {
       MPlist p = new MPlist (Key, Val);
@@ -103,8 +161,14 @@ namespace M17N.Core
       return this;
     }
 
-    public object Pop ()
+    public MPlist Push (object val)
+    {
+      return mplist_op (Push, val);
+    }
+
+    public object Pop (out MSymbol key)
     {
+      key = Key;
       if (IsEmpty)
        return null;
 
@@ -116,6 +180,12 @@ namespace M17N.Core
       return val;
     }
 
+    public object Pop ()
+    {
+      MSymbol key;
+      return Pop (out key);
+    }
+
     public MPlist Add (MSymbol key, object val)
     {
       MPlist p;
@@ -166,4 +236,221 @@ namespace M17N.Core
       }
     }
   }
+
+  public class MStreamReader : StreamReader
+  {
+    private static char[] escaped_char = new char[128];
+    private static int[] hexadecimal = new int[128];
+
+    public MStreamReader (Stream stream) : base (stream)
+      {
+      }
+
+    static MStreamReader ()
+      {
+       for (int i = 0; i < 128; i++)
+         escaped_char[i] = (char) i;
+       escaped_char['e'] = (char) 27;
+       escaped_char['b'] = '\b';
+       escaped_char['f'] = '\f';
+       escaped_char['n'] = '\n';
+       escaped_char['r'] = '\r';
+       escaped_char['t'] = '\t';
+       escaped_char['\\'] = '\\';
+       for (int i = 0; i < 128; i++)
+         hexadecimal[i] = -1;
+       for (int i = '0'; i <= '9'; i++)
+         hexadecimal[i] = i - '0';
+       for (int i = 'A'; i <= 'F'; i++)
+         hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
+      }
+
+    internal int PeekChar ()
+    {
+      bool comment = false;
+      int c;
+
+      while ((c = Peek ()) != -1)
+       {
+         if (comment)
+           {
+             if ((c = Read ()) == '\n')
+               comment = false;
+           }
+         else
+           {
+             if (c == ';')
+               comment = true;
+             else if (c != ' ' && c != '\t' && c != '\n')
+               return c;
+             Read ();
+           }
+       }
+      return c;
+    }
+
+    internal int ReadHexadecimal ()
+    {
+      int i = 0, c;
+
+      while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
+       {
+         Read ();
+         i = (i * 16) + c;
+       }
+      return i;
+    }
+
+    internal int ReadInteger ()
+    {
+      int i = 0, c;
+
+      while ((c = Peek ()) >= '0' && c <= '9')
+       i = (i * 10) + (Read () - '0');
+      return i;
+    }
+
+    internal int ReadChar ()
+    {
+      int c = Read ();
+
+      if (c == '\\')
+       {
+         c = Read ();
+         if (c == -1)
+           return -1;
+         if (c == 'x' || c == 'u')
+           return ReadHexadecimal ();
+         if (c < 128)
+           c = escaped_char[c];
+       }
+      return c;
+    }
+
+    internal MText ReadMtext ()
+    {
+      MText mt = new MText ();
+      int c;
+
+      while ((c = Peek ()) != -1 && c != '"')
+       {
+         if (c == '\\')
+           {
+             c = ReadChar ();
+             if (Peek () == '\n')
+               {
+                 ReadChar ();
+                 continue;
+               }
+             if (c == -1)
+               {
+                 mt.Cat ('\\');
+                 break;
+               }
+             mt.Cat (c);
+           }
+         else
+           mt.Cat (Read ());
+       }
+      if (c == '"')
+       Read ();
+      return mt;
+    }
+
+    internal string ReadSymbolName ()
+    {
+      int c = Peek ();
+
+      if (c == -1 || c == '(' || c == ' ' || c == '\n' || c == '"')
+       return "";
+      Read ();
+      if (c == '\\')
+       {
+         c = Read ();
+         if (c == -1)
+           c = '\\';
+       }
+      return (char) c + ReadSymbolName ();
+    }
+
+    internal bool ReadElement (out MSymbol key, out object val)
+    {
+      int c = PeekChar ();
+
+      if (c == '(')
+       {
+         Read ();
+         val = new MPlist (this);
+         key = MSymbol.plist;
+       }
+      else if (c == '"')
+       {
+         Read ();
+         val = ReadMtext ();
+         key = MSymbol.mtext;
+       }
+      else if (c >= '0' && c <= '9')
+       {
+         int i = ReadInteger ();
+
+         val = i;
+         key = MSymbol.integer;
+       }
+      else if (c == '-')
+       {
+         Read ();
+         c = Peek ();
+         if (c >= '0' && c <= '9')
+           {
+             int i = ReadInteger ();
+             val = - i;
+             key = MSymbol.integer;
+           }
+         else
+           {
+             string str = ReadSymbolName ();
+
+             val = new MSymbol ("-" + str);
+             key = MSymbol.symbol;
+           }
+       }
+      else if (c == '?')
+       {
+         Read ();
+         val = ReadChar ();
+         key = MSymbol.integer;
+       }
+      else if (c == '#')
+       {
+         Read ();
+         if ((c = Peek ()) == 'x' || c == 'u')
+           {
+             Read ();
+             val = ReadHexadecimal ();
+             key = MSymbol.integer;
+           }
+         else
+           {
+             string str = ReadSymbolName ();
+
+             val = new MSymbol ("#" + (char) c + str);
+             key = MSymbol.symbol;
+           }
+       }
+      else if (c == -1 || c == ')')
+       {
+         if (c == ')')
+           Read ();
+         val = null;
+         key = MSymbol.nil;
+         return false;
+       }
+      else
+       {
+         val = new MSymbol (ReadSymbolName ());
+         key = MSymbol.symbol;
+       }
+      return true;
+    }
+  }
 }