2012/06/17(日)Jsonほぼ互換の似非バリアント的な何か。
似非バリアント もしくは、似非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;
}
}
}
}