X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=MPlist.cs;h=6b89ac1f3e6da2e752cb8cec034202360e134749;hb=fb794190cd47986816f1a80de315cf1274a074d5;hp=7c81701d9688ff3a34325afe7902adfbf0e7bce6;hpb=7c46edd97138e0860a5b620f410e59f7a40a68ea;p=m17n%2Fm17n-lib-cs.git diff --git a/MPlist.cs b/MPlist.cs index 7c81701..6b89ac1 100644 --- a/MPlist.cs +++ b/MPlist.cs @@ -1,102 +1,411 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.IO; +using M17N; using M17N.Core; namespace M17N.Core { public class MPlist : IEnumerable { - public MSymbol Key; - public object Val; - private MPlist next; + public MSymbol key; + public object val; + public MPlist next; + + public MSymbol Key { get { return key; } } + public object Val { get { return val; } } + public MPlist Next { get { return next; } } + + private static List wf_keys; + + static MPlist () + { + wf_keys = new List (); + wf_keys.Add (MSymbol.symbol); + wf_keys.Add (MSymbol.mtext); + wf_keys.Add (MSymbol.plist); + wf_keys.Add (MSymbol.integer); + } public MPlist () - { - Key = MSymbol.nil; - Val = null; - } + { + key = MSymbol.nil; + val = null; + } + + public MPlist (FileStream stream) + { + MStreamReader reader = new MStreamReader (stream); + bool result = reader.ReadElement (out key, out val); + + if (result) + next = new MPlist (reader); + } + + public MPlist (FileStream stream, int count) + { + MStreamReader reader = new MStreamReader (stream); + bool result = reader.ReadElement (out key, out val); + + if (result && --count > 0) + next = new MPlist (reader, count); + else + next = new MPlist (); + } + + public MPlist (FileStream stream, MSymbol stop) + { + MStreamReader reader = new MStreamReader (stream); + bool result; + + key = MSymbol.nil; + val = null; + while (true) + { + MSymbol this_key; + object this_val; + + result = reader.ReadElement (out this_key, out this_val); + if (! result) + return; + if (this_key == MSymbol.plist) + { + MPlist plist = (MPlist) this_val; + + if (plist.IsSymbol && plist.Symbol == stop) + return; + } + key = this_key; + val = this_val; + next = new MPlist (reader, stop); + } + } + + public MPlist (FileStream stream, MSymbol target, MSymbol stop) + { + MStreamReader reader = new MStreamReader (stream); + bool result; + + key = MSymbol.nil; + val = null; + while (true) + { + MSymbol this_key; + object this_val; + + result = reader.ReadElement (out this_key, out this_val); + if (! result) + return; + if (this_key == MSymbol.plist) + { + MPlist plist = (MPlist) this_val; + + if (plist.IsSymbol) + { + if (plist.Symbol == stop) + return; + if (plist.Symbol == target) + { + key = target; + val = this_val; + next = new MPlist (); + return; + } + } + } + } + } + + internal MPlist (MStreamReader reader) + { + bool result = reader.ReadElement (out key, out val); + + if (result) + next = new MPlist (reader); + } + + private MPlist (MStreamReader reader, int count) + { + bool result = reader.ReadElement (out key, out val); + + if (result && --count > 0) + next = new MPlist (reader, count); + else + next = new MPlist (); + } + + private MPlist (MStreamReader reader, MSymbol stop) + { + bool result; + MPlist next_plist = null; + + key = MSymbol.nil; + val = null; + while (true) + { + MSymbol this_key; + object this_val; + + result = reader.ReadElement (out this_key, out this_val); + if (! result) + return; + if (this_key == MSymbol.plist) + { + MPlist plist = (MPlist) this_val; + + if (plist.IsSymbol && plist.Symbol == stop) + return; + } + if (next_plist == null) + { + key = this_key; + val = this_val; + next = next_plist = new MPlist (); + } + else + { + next_plist.key = this_key; + next_plist.val = this_val; + next_plist.next = new MPlist (); + next_plist = next_plist.next; + } + } + } + + private MPlist (MStreamReader reader, MSymbol target, MSymbol stop) + { + bool result; + + key = MSymbol.nil; + val = null; + while (true) + { + MSymbol this_key; + object this_val; + + result = reader.ReadElement (out this_key, out this_val); + if (! result) + return; + if (this_key == MSymbol.plist) + { + MPlist plist = (MPlist) this_val; + + if (plist.IsSymbol) + { + if (plist.Symbol == stop) + return; + if (plist.Symbol == target) + { + key = target; + val = this_val; + next = new MPlist (); + return; + } + } + } + } + } - private MPlist (MSymbol key, object val) + protected MPlist (MSymbol key, object val) { - Key = key; - Val = val; + this.key = key; + this.val = val; } public bool IsEmpty { get { return next == null; } } - public new string ToString () - { - string str = ""; + public bool IsSymbol { get { return Key == MSymbol.symbol; } } + public bool IsMText { get { return Key == MSymbol.mtext; } } + public bool IsPlist { get { return Key == MSymbol.plist; } } + public bool IsInteger { get { return Key == MSymbol.integer; } } - for (MPlist p = this; ! p.IsEmpty; p = p.next) + public MSymbol Symbol { get { return (MSymbol) val; } } + public MText Text { get { return (MText) val; } } + public MPlist Plist { get { return (MPlist) val; } } + public int Integer { get { return (int) val; } } + + public int Count + { + get { - str += (p == this ? "(" : " ") + p.Key.ToString () + ":"; - if (p.Val is MSymbol) - str += ((MSymbol) p.Val).ToString (); - else if (p.Val is MPlist) - str += ((MPlist) p.Val).ToString (); + int i = 0; + + for (MPlist p = this; p.next != null; i++, p = p.next); + return i; } - return str + ")"; } - public MPlist find (MSymbol key) + public MPlist this[int i] + { + get { + MPlist p; + for (p = this; ! p.IsEmpty && i > 0; i--, p = p.next); + return (i == 0 ? p : null); + } + } + + public MPlist Clone () + { + MPlist plist = new MPlist (), pl = plist; + + for (MPlist p = this; p.next != null; p = p.next) + pl = pl.Add (p.key, p.val); + return plist; + } + + public override string ToString () + { + string str = "("; + + for (MPlist p = this; ! p.IsEmpty; p = p.next) + { + if (p != this) + str += " "; + if (! wf_keys.Contains (p.key)) + str += p.key + ":"; + if (p.key == MSymbol.mtext) + str += "\"" + p.val + "\""; + else + str += p.val; + } + return str + ")"; + } + + private MPlist find (MSymbol key) { MPlist p; for (p = this; ! p.IsEmpty; p = p.next) - if (p.Key == key) + if (p.key == key) break; return p; } - public object get (MSymbol key) + public MPlist Find (MSymbol key) + { + MPlist p = find (key); + + return (p.IsEmpty ? null : p); + } + + public object Get (MSymbol key) { - return find (key).Val; + return find (key).val; } - public MPlist put (MSymbol key, object val) + internal MPlist Assq (MSymbol key) { - MPlist p = find (key); + foreach (MPlist p in this) + if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key) + return p; + return null; + } - if (p.IsEmpty) - return p.push (key, val); - p.Val = val; - return p; + 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 push (MSymbol key, object val) + public MPlist Set (MSymbol key, object val) { - MPlist p = new MPlist (Key, Val); + if (IsEmpty) + Push (key, val); + else + this.val = val; + 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 (this.key, this.val); p.next = this.next; - Key = key; - Val = val; + this.key = key; + this.val = val; next = p; return this; } - public object pop () + public MPlist Push (object val) + { + return mplist_op (Push, val); + } + + public object Pop (out MSymbol key) { + key = this.key; if (IsEmpty) return null; - object val = Val; + object this_val = val; - Key = next.Key; - Val = next.Val; + this.key = next.key; + this.val = next.val; next = next.next; - return val; + return this_val; + } + + public object Pop () + { + MSymbol temp; + return Pop (out temp); } - public MPlist add (MSymbol key, object val) + public MPlist Add (MSymbol key, object val) { MPlist p; for (p = this; ! p.IsEmpty; p = p.next); - return p.push (key, val); + return p.Push (key, val); + } + + public MPlist Cons (MSymbol key, object val) + { + MPlist plist = new MPlist (); + plist.key = key; + plist.val = val; + plist.next = this; + return plist; + } + + public MPlist Clear () + { + key = MSymbol.nil; + val = null; + next = null; + return this; } // Implement IEnumerable interface. + // foreach (MPlist p in plist) { ... } public virtual IEnumerator GetEnumerator () { @@ -131,12 +440,336 @@ namespace M17N.Core { if (current == null) current = plist; - else if (current.IsEmpty) - return false; else current = current.next; - return true; + return (! current.IsEmpty); + } + } + } + + public class MStreamReader : StreamReader + { + private static char[] escaped_char = new char[128]; + private static int[] hexadecimal = new int[128]; + private char comment_start; + private bool line_oriented; + + public MStreamReader (Stream stream) : base (stream) + { + comment_start = ';'; + line_oriented = false; } + + public MStreamReader (Stream stream, char comment_start, + bool line_oriented) : base (stream) + { + this.comment_start = comment_start; + this.line_oriented = line_oriented; + } + + static MStreamReader () + { + for (int i = 0; i < 128; i++) + escaped_char[i] = (char) i; + escaped_char['0'] = (char) 0; + escaped_char['e'] = (char) 27; + escaped_char['a'] = '\a'; + escaped_char['b'] = '\b'; + escaped_char['f'] = '\f'; + escaped_char['n'] = '\n'; + escaped_char['r'] = '\r'; + escaped_char['t'] = '\t'; + escaped_char['v'] = '\v'; + 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; + } + + private int ReadHexadecimal (int max) + { + int i = 0, c; + + while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0) + { + if (max >= 0 && (i * 16) + c >= max) + break; + Read (); + i = (i * 16) + c; + } + return i; + } + + public bool ForwardLine () + { + int c; + while ((c = Read ()) >=0 && c != '\n'); + return (c == '\n'); + } + + public bool SkipSpace (out int c) + { + while ((c = Peek ()) == ' ' && c == '\t' && c == '\f') + Read (); + return (c >= 0); + } + + public bool PeekChar (out int c) + { + while ((c = Peek ()) != -1) + { + if (c == comment_start) + ForwardLine (); + else if (c != ' ' && c != '\t' && c != '\n') + return true; + else if (c == '\n' && line_oriented) + return false; + else + Read (); + } + return false; + } + + public bool ReadInteger (out int i) + { + int c = Peek (); + + i = 0; + if (c < 0) + return false; + if (c == '0') + { + Read (); + c = Peek (); + if (c == 'x') + { + Read (); + i = ReadHexadecimal (-1); + return true; + } + } + while ((c = Peek ()) >= '0' && c <= '9') + i = (i * 10) + (Read () - '0'); + return true; + } + + public bool ReadChar (out int c) + { + c = Read (); + if (c < 0 || (line_oriented && c == '\n')) + return false; + if (c == '\\') + { + c = Read (); + if (c == '\n') + return ReadChar (out c); + if (c < 0) + c = '\\'; + else if (c == 'x' || c == 'u' || c == 'U') + c = ReadHexadecimal (0x10FFFF); + else if (c < 128) + c = escaped_char[c]; + } + return true; + } + + private bool read_string (out string str, int prefix, bool for_symbol) + { + char[] buf = new char[256]; + int c; + int i = 0; + + str = null; + if (prefix >= 0) + buf[i++] = (char) prefix; + while ((c = Peek ()) >= 0 + && c != '\"' + && (! for_symbol + || (c != '(' && c != ')' && c != ' ' && c != '\t' && c != '\n'))) + { + if (! ReadChar (out c)) + break; + if (c < 0x10000) + { + buf[i++] = (char) c; + } + else + { + buf[i++] = (char) (0xD800 + ((c - 0x10000) >> 10)); + buf[i++] = (char) (0xDC00 + ((c - 0x10000) & 0x3FF)); + } + if (i >= 255) + { + if (str == null) + str = new string (buf, 0, i); + else + str += new string (buf, 0, i); + i = 0; + } + } + if (c == '\"' && ! for_symbol) + Read (); + if (i > 0) + { + if (str == null) + str = new string (buf, 0, i); + else + str += new string (buf, 0, i); + } + return (str != null); + } + + public bool ReadString (out string str) + { + return read_string (out str, -1, false); + } + + public bool ReadMText (out MText mt) + { + int c = Peek (); + + if (c == '"') + { + string str; + + Read (); + if (read_string (out str, -1, false)) + mt = new MText (str); + else + mt = new MText (); + return true; + } + mt = new MText (); + if (c == '\\') + { + while ((c = Peek ()) == '\\') + { + Read (); + c = Peek (); + if (c != 'x') + break; + Read (); + mt.Cat (ReadHexadecimal (0x10FFFF)); + } + return true; + } + return false; + } + + public bool ReadSymbol (out MSymbol sym, int prefix) + { + string str; + + if (read_string (out str, prefix, true)) + { + sym = MSymbol.Of (str); + return true; + } + sym = MSymbol.nil; + return false; + } + + internal bool ReadElement (out MSymbol key, out object val) + { + int c; + + if (! PeekChar (out c)) + { + val = null; + key = MSymbol.nil; + return false; + } + + if (c == '(') + { + Read (); + val = new MPlist (this); + key = MSymbol.plist; + } + else if (c == '"') + { + MText mt; + ReadMText (out mt); + val = mt; + key = MSymbol.mtext; + } + else if (c >= '0' && c <= '9') + { + int i; + ReadInteger (out i); + val = i; + key = MSymbol.integer; + } + else if (c == '-') + { + Read (); + c = Peek (); + if (c >= '0' && c <= '9') + { + int i; + ReadInteger (out i); + val = - i; + key = MSymbol.integer; + } + else + { + MSymbol sym; + + ReadSymbol (out sym, '-'); + val = sym; + key = MSymbol.symbol; + } + } + else if (c == '?') + { + Read (); + if (ReadChar (out c)) + { + val = c; + key = MSymbol.integer; + } + else + { + val = null; + key = MSymbol.nil; + } + } + else if (c == '#') + { + Read (); + if ((c = Peek ()) == 'x' || c == 'u') + { + Read (); + val = ReadHexadecimal (-1); + key = MSymbol.integer; + } + else + { + MSymbol sym; + + ReadSymbol (out sym, '#'); + val = sym; + key = MSymbol.symbol; + } + } + else if (c == ')') + { + Read (); + val = null; + key = MSymbol.nil; + return false; + } + else + { + MSymbol sym; + + ReadSymbol (out sym, -1); + val = sym; + key = MSymbol.symbol; + } + return true; } } }