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; 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; } 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; } } } } } protected MPlist (MSymbol key, object val) { this.key = key; this.val = val; } public bool IsEmpty { get { return next == null; } } 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; } } 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 { int i = 0; for (MPlist p = this; p.next != null; i++, p = p.next); return i; } } 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) break; return p; } public MPlist Find (MSymbol key) { MPlist p = find (key); return (p.IsEmpty ? null : p); } public object Get (MSymbol key) { return find (key).val; } internal MPlist Assq (MSymbol key) { foreach (MPlist p in this) if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key) return p; return null; } 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) Push (key, val); else { this.key = key; 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; this.key = key; this.val = val; next = p; return this; } public MPlist Push (object val) { return mplist_op (Push, val); } public object Pop (out MSymbol key) { key = this.key; if (IsEmpty) return null; object this_val = val; this.key = next.key; this.val = next.val; next = next.next; return this_val; } public object Pop () { MSymbol temp; return Pop (out temp); } public MPlist Add (MSymbol key, object val) { MPlist p; for (p = this; ! p.IsEmpty; p = p.next); 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 () { return new Enumerator (this); } private class Enumerator : IEnumerator { private MPlist plist; private MPlist current; internal Enumerator (MPlist plist) { this.plist = plist; } public object Current { get { if (current == null || current.IsEmpty) throw new InvalidOperationException (); return current; } } public void Reset () { current = null; } public bool MoveNext () { if (current == null) current = plist; else current = current.next; 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; } } }