2012/06/17(Sun)Jsonほぼ互換の似非バリアント的な何か。

はてブ数 2012/06/17 18:22 プログラミング::C# つーさ

似非バリアント もしくは、似非JSONオブジェクト。
Jsonパーサ・フォーマッタの独自実装ですはい。
ゲームとかのセーブデータをスキーマレスに読み書きしたいなという欲求があるからして。

    class VarTest
    {
        public static void TestVar()
        {
            Var v = new VarList {
                true,
                false,
                12345,
                "ほげ",
                new byte[]{0x1, 0x2, 3, 4, 5, },
                new VarDictionary() { 
                    {"あ", true}, 
                    {"い", false}, 
                    {"X", Var.Null}, 
                    {"Y", 123},
                    {"辞書", new VarDictionary() { 
                        {"あ", true}, {"い", false}, {"X", new Var()}, {"Y", 123}, 
                    } },
                    {"辞書内配列", new VarDictionary() { 
                        {"あ", new int[]{123,456 } }, 
                        {"い", new bool[]{true, true, false, false, true} }, 
                        {"X", new VarList { Var.Null, "えー", new byte[]{99, 99, 99}, } },
                        {"Y", new string[]{"う゛ぁ", "う゛ぃ",} },
                    } }
                },
                "にゃー",
            };

            int a = v[5]["辞書内配列"]["あ"][1]; // → 456
            string b = v[5]["辞書内配列"]["X"][1]; // → "えー"
            Console.WriteLine(a);
            Console.WriteLine(b);
            string serialized = v.ToFormattedString(); // JSON形式の文字列になる
            Console.WriteLine(serialized);
            Var readed = Var.FromFormattedString(serialized); // JSON形式の文字列から読み込む
            Console.WriteLine(readed.ToFormattedString()); // ちゃんと読み込めたか?
        }
    }

のような。
読み込み時に備えて、Nullとは別にundefindも定義しておくべきだったかしら。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace Tsukikage.GameSDK.Util
{
    /// <summary>
    /// 似非バリアント型。Jsonのような(実数が扱えない、byte配列を扱う独自拡張をしてる、文法チェックが緩い)
    /// </summary>
    [StructLayout(LayoutKind.Explicit)]
    public struct Var : IComparable<Var>, IEquatable<Var>, ICloneable
    {
        [FieldOffset(0)]
        private VarType type;

        [FieldOffset(4)]
        private object asObject;

        [FieldOffset(4)]
        private VarList asList;

        [FieldOffset(4)]
        private VarDictionary asDictionary;

        [FieldOffset(4)]
        private string asString;

        [FieldOffset(4)]
        private byte[] asByteArray;

        [FieldOffset(8)]
        private bool asBool;

        [FieldOffset(8)]
        private long asInt;

        /// <summary>
        /// サポートしている型
        /// </summary>
        public enum VarType : byte
        {
            Null = 0x00,
            Boolean = 0x01,
            Int = 0x02,
            String = 0x03,
            ByteArray = 0x04,

            List = 0x10,
            Dictionary = 0x20,
        }

        public bool IsNull { get { return type == VarType.Null; } }

        public bool IsBoolean { get { return type == VarType.Boolean; } }
        public bool IsInt { get { return type == VarType.Int; } }
        public bool IsString { get { return type == VarType.String; } }
        public bool IsBinary { get { return type == VarType.ByteArray; } }
        public bool IsList { get { return type == VarType.List; } }
        public bool IsDictionary { get { return type == VarType.Dictionary; } }

        public bool AsBoolean { get { return (bool)this; } }
        public int AsInt { get { return (int)this; } }
        public string AsString { get { return (string)this; } }
        public byte[] AsBinary { get { return (byte[])this; } }
        public VarList AsList { get { return (VarList)this; } }
        public VarDictionary AsDictionary { get { return (VarDictionary)this; } }

        public static implicit operator bool(Var v)
        {
            if (v.IsNull) return default(bool);
            if (v.IsBoolean) return v.asBool;
            throw new InvalidCastException("Var[" + v.type + "]型からbool型への変換はサポートしません。");
        }

        public static implicit operator int(Var v)
        {
            if (v.IsNull) return default(int);
            if (v.IsInt) return (int)v.asInt;
            throw new InvalidCastException("Var[" + v.type + "]型からint型への変換はサポートしません。");
        }

        public static implicit operator long(Var v)
        {
            if (v.IsNull) return default(int);
            if (v.IsInt) return v.asInt;
            throw new InvalidCastException("Var[" + v.type + "]型からlong型への変換はサポートしません。");
        }

        public static implicit operator double(Var v)
        {
            if (v.IsNull) return default(int);
            if (v.IsInt) return v.asInt;
            throw new InvalidCastException("Var[" + v.type + "]型からdouble型への変換はサポートしません。");
        }

        public static implicit operator string(Var v)
        {
            if (v.IsNull) return default(string);
            if (v.IsString) return v.asString;
            throw new InvalidCastException("Var[" + v.type + "]型からstring型への変換はサポートしません。");
        }

        public static implicit operator byte[](Var v)
        {
            if (v.IsNull) return default(byte[]);
            if (v.IsBinary) return v.asByteArray;
            throw new InvalidCastException("Var[" + v.type + "]型からbyte[]型への変換はサポートしません。");
        }

        public static implicit operator VarList(Var v)
        {
            if (v.IsNull) return default(VarList);
            if (v.IsList) return v.asList;
            throw new InvalidCastException("Var[" + v.type + "]型からVarList型への変換はサポートしません。");
        }

        public static implicit operator VarDictionary(Var v)
        {
            if (v.IsNull) return default(VarDictionary);
            if (v.IsDictionary) return v.asDictionary;
            throw new InvalidCastException("Var[" + v.type + "]型からVarDictionary型への変換はサポートしません。");
        }

        public static implicit operator Var(bool data) { return new Var(data); }
        public static implicit operator Var(byte[] data) { return new Var(data); }
        public static implicit operator Var(long data) { return new Var(data); }
        public static implicit operator Var(string data) { return new Var(data); }
        public static implicit operator Var(VarList data) { return new Var(data); }
        public static implicit operator Var(VarDictionary data) { return new Var(data); }

        public int Count
        {
            get
            {
                if (IsList) return asList.Count;
                if (IsDictionary) return asDictionary.Count;
                if (IsNull) return 0;
                throw new InvalidOperationException("指定されたVar型変数はListまたはDictionaryではありません。");
            }
        }

        public Var this[int index]
        {
            get
            {
                if (IsList) return asList[index];
                throw new InvalidOperationException("指定されたVar型変数は配列ではありません。");
            }

            set
            {
                if (IsList) { asList[index] = value; return; }
                throw new InvalidOperationException("指定されたVar型変数は配列ではありません。");
            }
        }

        public Var this[string key]
        {
            get
            {
                if (IsDictionary) return asDictionary[key];
                throw new InvalidOperationException("指定されたVar型変数はVarDictionaryではありません。");
            }

            set
            {
                if (IsDictionary) { asDictionary[key] = value; return; }
                throw new InvalidOperationException("指定されたVar型変数はVarDictionaryではありません。");
            }
        }

        public new VarType GetType() { return type; }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            switch (type)
            {
                case VarType.Null: return null;
                case VarType.Boolean: return asBool.ToString();
                case VarType.Int: return asInt.ToString();
                case VarType.String: return asString;
                case VarType.ByteArray: return "{Binary}";
                case VarType.List: return ToFormattedString();
                case VarType.Dictionary: return ToFormattedString();
                default:
                    throw new Exception("指定されたVar型は状態が変です。");
            }
        }

        public static Var Null { get { return new Var(); } }

        private Var(bool data) : this() { this.type = VarType.Boolean; this.asBool = data; }
        private Var(long data) : this() { this.type = VarType.Int; this.asInt = data; }
        private Var(byte[] data) : this() { this.type = VarType.ByteArray; this.asByteArray = data; }
        private Var(string data) : this() { this.type = VarType.String; this.asString = data; }
        private Var(VarList data) : this() { this.type = VarType.List; this.asList = data; }
        private Var(VarDictionary data) : this() { this.type = VarType.Dictionary; this.asDictionary = data; }

        public static bool operator <(Var a, Var b) { return a.CompareTo(b) < 0; }
        public static bool operator >(Var a, Var b) { return a.CompareTo(b) > 0; }
        public static bool operator <=(Var a, Var b) { return a.CompareTo(b) <= 0; }
        public static bool operator >=(Var a, Var b) { return a.CompareTo(b) >= 0; }
        public static bool operator ==(Var a, Var b) { return a.Equals(b); }
        public static bool operator !=(Var a, Var b) { return !a.Equals(b); }

        public static int operator +(Var a)
        {
            if (a.IsInt) return a;
            throw new NotImplementedException(a.type + "型を+できません。");
        }

        public static Var operator +(Var a, Var b)
        {
            if (a.IsInt && b.IsInt) return (int)a + (int)b;
            if (a.IsString || b.IsString) return a.ToString() + b.ToString();
            throw new NotImplementedException(a.type + "型に" + b.type + "型を+できません。");
        }

        public static string operator +(string a, Var b) { return a + b.ToString(); }
        public static string operator +(Var a, string b) { return a.ToString() + b; }

        public struct VarInt
        {
            long value;
            public VarInt(long value) { this.value = value; }
            public static implicit operator int(VarInt v) { return (int)v.value; }
            public static implicit operator long(VarInt v) { return v.value; }
            public static implicit operator double(VarInt v) { return v.value; }
            public static implicit operator Var(VarInt v) { return new Var(v.value); }
            public static implicit operator VarInt(long v) { return new VarInt(v); }
        }

        public struct VarBool
        {
            bool value;
            public VarBool(bool value) { this.value = value; }
            public static implicit operator bool(VarBool v) { return v.value; }
            public static implicit operator Var(VarBool v) { return new Var(v.value); }
            public static implicit operator VarBool(bool v) { return new VarBool(v); }
        }

        public static Var operator ++(Var a)
        {
            if (a.IsInt) return (int)a + 1;
            throw new NotImplementedException(a.type + "型を++できません。");
        }

        public static VarInt operator -(Var a)
        {
            if (a.IsInt) return -(long)a;
            throw new NotImplementedException(a.type + "型を-できません。");
        }

        public static VarInt operator -(Var a, Var b)
        {
            if (a.IsInt && b.IsInt) return (int)a - (int)b;
            throw new NotImplementedException(a.type + "型に" + b.type + "型を-できません。");
        }

        public static Var operator --(Var a)
        {
            if (a.IsInt) return (long)a - 1;
            throw new NotImplementedException(a.type + "型を--できません。");
        }

        public static VarInt operator *(Var a, Var b)
        {
            if (a.IsInt && b.IsInt) return (long)a * (long)b;
            throw new NotImplementedException(a.type + "型に" + b.type + "型を*できません。");
        }

        public static VarInt operator /(Var a, Var b)
        {
            if (a.IsInt && b.IsInt) return (long)a / (long)b;
            throw new NotImplementedException(a.type + "型に" + b.type + "型を/できません。");
        }

        public static VarInt operator %(Var a, int b)
        {
            if (a.IsInt) return (long)a % b;
            throw new NotImplementedException(a.type + "型にint型を%できません。");
        }

        public static VarInt operator <<(Var a, int b)
        {
            if (a.IsInt) return (long)a << b;
            throw new NotImplementedException(a.type + "型にint型を<<できません。");
        }

        public static VarInt operator >>(Var a, int b)
        {
            if (a.IsInt) return (long)a >> b;
            throw new NotImplementedException(a.type + "型にint型を>>できません。");
        }

        public static VarInt operator |(long a, Var b)
        {
            if (b.IsInt) return (long)a | (long)b;
            throw new NotImplementedException(VarType.Int + "型に" + b.type + "型を|できません。");
        }

        public static VarInt operator |(Var a, long b)
        {
            if (a.IsInt) return (long)a | (long)b;
            throw new NotImplementedException(a.type + "型に" + VarType.Int + "型を|できません。");
        }

        public static VarBool operator |(bool a, Var b)
        {
            if (b.IsBoolean) return (bool)a | (bool)b;
            throw new NotImplementedException(VarType.Boolean + "型に" + b.type + "型を|できません。");
        }

        public static VarBool operator |(Var a, bool b)
        {
            if (a.IsBoolean) return (bool)a | (bool)b;
            throw new NotImplementedException(a.type + "型に" + VarType.Boolean + "型を|できません。");
        }

        public static Var operator |(Var a, Var b)
        {
            if (a.IsBoolean && b.IsBoolean) return (bool)a | (bool)b;
            if (a.IsInt && b.IsInt) return (long)a | (long)b;
            throw new NotImplementedException(a.type + "型に" + b.type + "型を|できません。");
        }

        public static VarInt operator &(long a, Var b)
        {
            if (b.IsInt) return (long)a & (long)b;
            throw new NotImplementedException(VarType.Int + "型と" + b.type + "型を&できません。");
        }

        public static VarInt operator &(Var a, long b)
        {
            if (a.IsInt) return (long)a & (long)b;
            throw new NotImplementedException(a.type + "型と" + VarType.Int + "型を&できません。");
        }

        public static VarBool operator &(bool a, Var b)
        {
            if (b.IsBoolean) return (bool)a & (bool)b;
            throw new NotImplementedException(VarType.Boolean + "型と" + b.type + "型を&できません。");
        }

        public static VarBool operator &(Var a, bool b)
        {
            if (a.IsBoolean) return (bool)a & (bool)b;
            throw new NotImplementedException(a.type + "型と" + VarType.Boolean + "型を&できません。");
        }

        public static Var operator &(Var a, Var b)
        {
            if (a.IsBoolean && b.IsBoolean) return (bool)a & (bool)b;
            if (a.IsInt && b.IsInt) return (long)a & (long)b;
            throw new NotImplementedException(a.type + "型と" + b.type + "型を&できません。");
        }

        public static VarInt operator ^(long a, Var b)
        {
            if (b.IsInt) return (long)a ^ (long)b;
            throw new NotImplementedException(VarType.Int + "型と" + b.type + "型を^できません。");
        }

        public static VarInt operator ^(Var a, long b)
        {
            if (a.IsInt) return (long)a ^ (long)b;
            throw new NotImplementedException(a.type + "型と" + VarType.Int + "型を^できません。");
        }

        public static VarBool operator ^(bool a, Var b)
        {
            if (b.IsBoolean) return (bool)a ^ (bool)b;
            throw new NotImplementedException(VarType.Boolean + "型と" + b.type + "型を^できません。");
        }

        public static VarBool operator ^(Var a, bool b)
        {
            if (a.IsBoolean) return (bool)a ^ (bool)b;
            throw new NotImplementedException(a.type + "型と" + VarType.Boolean + "型を^できません。");
        }

        public static Var operator ^(Var a, Var b)
        {
            if (a.IsBoolean && b.IsBoolean) return (bool)a ^ (bool)b;
            if (a.IsInt && b.IsInt) return (long)a ^ (long)b;
            throw new NotImplementedException(a.type + "型と" + b.type + "型を^できません。");
        }

        public static VarInt operator ~(Var a)
        {
            if (a.IsInt) return ~(long)a;
            throw new NotImplementedException(a.type + "型を~できません");
        }

        public static VarBool operator !(Var a)
        {
            if (a.IsBoolean) return !(bool)a;
            throw new NotImplementedException(a.type + "型を!できません");
        }

        public override int GetHashCode()
        {
            if (IsNull) throw new NullReferenceException();
            return ToString().GetHashCode();
        }

        public override bool Equals(object obj)
        {
            return obj is Var ? Equals((Var)obj) : false;
        }

        public bool Equals(Var obj)
        {
            if (this.type != obj.type) return false;
            if (IsInt) return asInt == obj.asInt;
            if (IsBoolean) return asBool == obj.asBool;
            return asObject.Equals(obj.asObject);
        }

        public int CompareTo(Var other)
        {
            if (IsBoolean && other.IsBoolean) return ((bool)this ? 1 : 0) - ((bool)other ? 1 : 0);
            if (IsInt && other.IsInt) return ((long)this).CompareTo((long)other);
            if (IsString && other.IsString) return ((string)this).CompareTo((string)other);
            throw new InvalidOperationException(type + "型と" + other.type + "型は比較できません。");
        }

        public static implicit operator Var(bool[] array)
        {
            return new VarList(Array.ConvertAll<bool, Var>(array, delegate(bool v) { return v; }));
        }

        public static implicit operator Var(int[] array)
        {
            return new VarList(Array.ConvertAll<int, Var>(array, delegate(int v) { return v; }));
        }

        public static implicit operator Var(long[] array)
        {
            return new VarList(Array.ConvertAll<long, Var>(array, delegate(long v) { return v; }));
        }

        public static implicit operator Var(string[] array)
        {
            return new VarList(Array.ConvertAll<string, Var>(array, delegate(string v) { return v; }));
        }

        public static implicit operator int[](Var array)
        {
            return Array.ConvertAll<Var, int>(array.AsList.ToArray(), delegate(Var v) { return v; });
        }

        public static implicit operator long[](Var array)
        {
            return Array.ConvertAll<Var, long>(array.AsList.ToArray(), delegate(Var v) { return v; });
        }

        public static implicit operator string[](Var array)
        {
            return Array.ConvertAll<Var, string>(array.AsList.ToArray(), delegate(Var v) { return v; });
        }

        public static implicit operator bool[](Var array)
        {
            return Array.ConvertAll<Var, bool>(array.AsList.ToArray(), delegate(Var v) { return v; });
        }

        string EncodeString(string input)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == '\n') sb.Append("\\n");
                else if (input[i] == '\\') sb.Append("\\\\");
                else if (input[i] == '\b') sb.Append("\\b");
                else if (input[i] == '\f') sb.Append("\\f");
                else if (input[i] == '\r') sb.Append("\\r");
                else if (input[i] == '\t') sb.Append("\\t");
                else if (input[i] == '\"') sb.Append("\\\"");
                else if (input[i] == '<') sb.Append("\\<");
                else if (input[i] == '>') sb.Append("\\>");
                //else if (input[i] > 127) sb.Append(string.Format("\\u{0:X4}", (int)input[i]));
                else sb.Append(input[i]);

            }
            return sb.ToString();
        }

        string ToFormattedString(int indent, bool uncompressed)
        {
            switch (type)
            {
                case VarType.Null: return "null";
                case VarType.Boolean: return asBool ? "true" : "false";
                case VarType.Int: return asInt.ToString();
                case VarType.String: return "\"" + EncodeString(asString) + "\"";
                case VarType.ByteArray:
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Append("B[");
                        for (int i = 0; i < asByteArray.Length; i++)
                            sb.Append(string.Format("{0:X2}", asByteArray[i]));
                        sb.Append(']');
                        return sb.ToString();
                    }
                case VarType.List:
                    {
                        if (asList.Count == 0)
                            return "[]";

                        StringBuilder sb = new StringBuilder();
                        sb.Append('[');
                        if (uncompressed) sb.Append('\n');
                        foreach (Var v in asList)
                        {
                            if (uncompressed) sb.Append(new string('\t', indent + 1));
                            sb.Append(v.ToFormattedString(indent + 1, uncompressed));
                            sb.Append(",");
                            if (uncompressed) sb.Append("\n");
                        }
                        if (uncompressed) sb.Remove(sb.Length - 1, 1);
                        sb.Remove(sb.Length - 1, 1);
                        if (uncompressed) sb.Append('\n');
                        if (uncompressed) sb.Append(new string('\t', indent));
                        sb.Append("]");
                        return sb.ToString();
                    }

                case VarType.Dictionary:
                    {
                        if (asDictionary.Count == 0)
                            return "{}";

                        StringBuilder sb = new StringBuilder();
                        sb.Append('{');
                        if (uncompressed) sb.Append('\n');
                        foreach (string key in asDictionary.Keys)
                        {
                            if (uncompressed) sb.Append(new string('\t', indent + 1));
                            sb.Append("\"" + EncodeString(key) + "\"");
                            if (uncompressed) sb.Append(' ');
                            sb.Append(':');
                            if (uncompressed) sb.Append(' ');
                            sb.Append(asDictionary[key].ToFormattedString(indent + 1, uncompressed));
                            sb.Append(',');
                            if (uncompressed) sb.Append('\n');
                        }
                        if (uncompressed) sb.Remove(sb.Length - 1, 1);
                        sb.Remove(sb.Length - 1, 1);
                        if (uncompressed) sb.Append('\n');
                        if (uncompressed) sb.Append(new string('\t', indent));
                        sb.Append("}");
                        return sb.ToString();
                    }

                default:
                    throw new Exception("指定されたVar型は状態が変です。");
            }
        }

        /// <summary>
        /// 比較的読みやすい文字列形式に変換します。
        /// </summary>
        /// <returns></returns>
        public string ToFormattedString()
        {
            return ToFormattedString(0, true);
        }

        /// <summary>
        /// インデントや改行を省いた1行の文字列形式に変換します。
        /// </summary>
        /// <returns></returns>
        public string ToCompressedFormattedString()
        {
            return ToFormattedString(0, false);
        }

        /// <summary>
        /// 一切の参照を共有しないオブジェクトの完全なコピーを作ります。でかいデータを含んでると遅いかも。
        /// </summary>
        /// <returns>コピー</returns>
        public Var Clone()
        {
            return FromFormattedString(ToCompressedFormattedString());
        }

        /// <summary>
        /// 一切の参照を共有しないオブジェクトの完全なコピーを作ります。でかいデータを含んでると遅いかも。
        /// </summary>
        /// <returns>コピー</returns>
        object ICloneable.Clone()
        {
            return Clone();
        }

        /// <summary>
        /// 文字列形式からVarを生成します。
        /// </summary>
        /// <param name="serialized">文字列</param>
        /// <exception cref="FormatException">文法エラー</exception>
        /// <returns></returns>
        public static Var FromFormattedString(string serialized) { return VarSerializer.Parse(serialized); }

        /// <summary>
        /// ストリームを読んでVarを生成します。ストリームはUtf8でエンコードされています。
        /// </summary>
        /// <param name="serialized">文字列</param>
        /// <exception cref="FormatException">文法エラー</exception>
        /// <returns></returns>
        public static Var FromFormattedStream(Stream serialized) { return VarSerializer.Load(serialized); }

        class VarSerializer
        {
            private VarSerializer(TextReader textReader)
            {
                this.textReader = textReader;
                this.readString = new StringBuilder(4096);
                next();
            }

            TextReader textReader;
            StringBuilder readString;

            char cur;

            void next()
            {
                int x = textReader.Read();
                if (x != -1)
                {
                    readString.Append((char)x);
                    cur = (char)x;
                }
                else
                {
                    cur = '\0';
                }
            }

            void abort(string message)
            {
                string[] lines = readString.ToString().Split('\n');
                throw new FormatException("文法エラー。" + message + "\n" + lines.Length + "行目 " + lines[lines.Length - 1] + " ←ここが変。");
            }

            void assert(bool exp, string message)
            {
                if (!exp) abort(message);
            }

            void assert(bool exp)
            {
                if (cur == '\0') assert(exp, "予期せぬEOFに出会いました。");
                else assert(exp, "解釈できませんでした。");
            }

            Var ReadObject()
            {
                SkipWhiteSpace();
                assert(cur != '\0');
                switch (cur)
                {
                    case '0': 
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '-': return ReadNumber();
                    case 'N':
                    case 'n': return ReadNull();
                    case 'T':
                    case 't': return ReadTrue();
                    case 'F':
                    case 'f': return ReadFalse();
                    case '"': return ReadString();
                    case '[': return ReadList();
                    case '{': return ReadDictionary();
                    case 'B': return ReadByteArray();
                    case '\0': assert(false); break;
                    default: assert(false); break;
                }
                return Var.Null; /* not reachable */
            }

            Var ReadNull()
            {
                assert(cur == 'n' || cur == 'N'); next();
                assert(cur == 'u' || cur == 'U'); next();
                assert(cur == 'l' || cur == 'L'); next();
                assert(cur == 'l' || cur == 'L'); next();
                return Var.Null;
            }

            Var ReadTrue()
            {
                assert(cur == 't' || cur == 'T'); next();
                assert(cur == 'r' || cur == 'R'); next();
                assert(cur == 'u' || cur == 'U'); next();
                assert(cur == 'e' || cur == 'E'); next();
                return true;
            }

            Var ReadFalse()
            {
                assert(cur == 'f' || cur == 'F'); next();
                assert(cur == 'a' || cur == 'A'); next();
                assert(cur == 'l' || cur == 'L'); next();
                assert(cur == 's' || cur == 'S'); next();
                assert(cur == 'e' || cur == 'E'); next();
                return false;
            }

            Var ReadNumber()
            {
                bool minus = false;
                long value = 0;

                if (cur == '-')
                {
                    minus = true;
                    next();
                }

                while (cur >= '0' && cur <= '9')
                {
                    value = value * 10 + (cur - '0');
                    next();
                }
                if (minus) return -value;
                return value;
            }

            Var ReadByteArray()
            {
                assert(cur == 'B'); next();
                assert(cur == '['); next();

                List<byte> bytes = new List<byte>();
                while (true)
                {
                    assert(cur != '\0');
                    if (cur == ']') break;
                    int b = Hex(cur); next();
                    b = b * 16 + Hex(cur); next();
                    bytes.Add((byte)b);
                }
                assert(cur == ']'); next();
                return bytes.ToArray();
            }

            VarList ReadList()
            {
                assert(cur == '['); next();
                VarList list = new VarList();
                while (true)
                {
                    SkipWhiteSpace();
                    if (cur == ']') break;
                    assert(cur != '\0');
                    list.Add(ReadObject());
                    SkipWhiteSpace();
                    assert(cur == ']' || cur == ',');
                    if (cur == ',') next();
                }

                next();
                return list;
            }

            VarDictionary ReadDictionary()
            {
                assert(cur == '{'); next();
                VarDictionary dict = new VarDictionary();
                while (true)
                {
                    SkipWhiteSpace();
                    if (cur == '}') break;
                    string key = ReadKey();
                    SkipWhiteSpace();
                    assert(cur == ':'); next();
                    SkipWhiteSpace();
                    dict.Add(key, ReadObject());
                    SkipWhiteSpace();
                    assert(cur == ',' || cur == '}');
                    if (cur == ',') next();
                }

                next();
                return dict;
            }

            void SkipWhiteSpace()
            {
                bool inBlockComment = false;
                bool inLinerComment = false;
                while (cur != '\0')
                {
                    if (inBlockComment)
                    {
                        if (cur == '*')
                        {
                            next();
                            if (cur == '/')
                            {
                                next();
                                inBlockComment = false;
                            }
                        }
                        else
                        {
                            next();
                        }
                    }
                    else if (inLinerComment)
                    {
                        if (cur == '\n')
                        {
                            inLinerComment = false;
                            next();
                        }
                        else
                        {
                            next();
                        }
                    }
                    else
                    {
                        if (cur <= ' ')
                        {
                            next();
                        }
                        else if (cur == '/')
                        {
                            next();
                            if (cur == '*')
                            {
                                inBlockComment = true;
                                next();
                            }
                            else if (cur == '/')
                            {
                                inLinerComment = true;
                                next();
                            }
                            else
                            {
                                abort("コメントかと思ったら違いました。");
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            string ReadKey()
            {
                if (cur == '"' || cur == '\'')
                    return ReadString();

                StringBuilder sb = new StringBuilder();
                while (cur > ' ' && cur != ':')
                {
                    assert(cur != '\0');
                    sb.Append(cur);
                    next();
                }
                return sb.ToString();
            }

            string ReadString()
            {
                assert(cur == '\"' || cur == '\'', "文字列?がQuoteで始まっていません。");

                char q = cur;
                StringBuilder sb = new StringBuilder();
                bool escape = false;
                while (true)
                {
                    assert(cur != '\0');
                    next();
                    if (escape)
                    {
                        escape = false;
                        switch (cur)
                        {
                            case 'n': sb.Append('\n'); break;
                            case 't': sb.Append('\t'); break;
                            case 'b': sb.Append('\b'); break;
                            case 'f': sb.Append('\f'); break;
                            case 'r': sb.Append('\r'); break;
                            case '"': sb.Append('"'); break;
                            case '\'': sb.Append('\''); break;
                            case '<': sb.Append('<'); break;
                            case '>': sb.Append('>'); break;
                            case 'u':
                                int u = Hex(cur);
                                u = u * 16 + Hex(cur);
                                u = u * 16 + Hex(cur);
                                u = u * 16 + Hex(cur);
                                sb.Append((char)u);
                                break;
                        }
                    }
                    else if (cur == '\\')
                    {
                        escape = true;
                    }
                    else if (cur == q)
                    {
                        next();
                        break;
                    }
                    else
                    {
                        sb.Append(cur);
                    }
                }
                return sb.ToString();
            }

            int Hex(char c)
            {
                if (c >= '0' && c <= '9') return c - '0';
                if (c >= 'A' && c <= 'F') return c - 'A' + 10;
                if (c >= 'a' && c <= 'f') return c - 'a' + 10;
                abort("16進数に変換できませんでした。");
                return 0; /* no reachable */
            }

            public static Var Load(Stream s)
            {
                return Read(new StreamReader(s));
            }

            public static Var Parse(string s)
            {
                return Read(new StringReader(s));
            }

            public static string ToString(Var v)
            {
                return v.ToString();
            }

            public static Var Read(TextReader textReader)
            {
                return new VarSerializer(textReader).ReadObject();
            }
        }
    }

    /// <summary>
    /// Var配列型
    /// </summary>
    public class VarList : List<Var>
    {
        /// <summary>
        /// 新しいVar配列を準備します。
        /// </summary>
        public VarList()
            : base()
        {
        }

        /// <summary>
        /// 新しいVar配列を準備します。
        /// </summary>
        /// <param name="collection">新しいオブジェクトにあらかじめコピーしておくデータ</param>
        public VarList(IEnumerable<Var> collection)
            : base(collection)
        {
        }
    }

    /// <summary>
    /// Varオブジェクト型
    /// </summary>
    public class VarDictionary : Dictionary<string, Var>
    {
        /// <summary>
        /// 新しいVarオブジェクトを準備します。
        /// </summary>
        public VarDictionary()
            : base()
        {
        }

        /// <summary>
        /// 新しいVarオブジェクト型を準備します。
        /// </summary>
        /// <param name="dictionary">新しいオブジェクトにあらかじめコピーしておくデータ</param>
        public VarDictionary(IDictionary<string, Var> dictionary)
            : base(dictionary)
        {
        }

        /// <summary>
        /// 指定したキーに関連付けられている値を取得します。
        /// おかしな値をとりだそうとするとVar.Nullが返ります。
        /// </summary>
        /// <param name="key">キー</param>
        /// <returns>値</returns>
        public new Var this[string key]
        {
            get
            {
                Var v;
                if (TryGetValue(key, out v))
                    return v;
                return Var.Null;
            }
            set
            {
                base[key] = value;
            }
        }
    }
}