/// <summary>数値(2進数)を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <returns>数値。</returns> private static ITomlValue Get2NumberValue(TomlInnerBuffer.TomlIter iter) { ulong v = 0; bool ud = false; UTF8 c; int point = iter.Pointer; // 数値を取得する while ((c = iter.GetChar(0)).ch1 != 0) { // 1. '_'の連続の判定 // 2. 数値の計算をする // 2-1. 数値の有効範囲を超えるならばエラー if (c.ch1 == '_') { if (ud) // 1 { throw new TomlAnalisysException(Resources.UNDERBAR_CONTINUE_ERR, iter); } ud = true; } else if (c.ch1 == '0' || c.ch1 == '1') { if (v <= ulong.MaxValue / 2) // 2 { v = v * 2 + (ulong)(c.ch1 - '0'); } else // 2-1 { throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter); } ud = false; } else { break; } iter.Skip(1); } // 一文字の数値もなければ None値を返す if (iter.Pointer == point) { return(TomlValue.Empty); } if (v <= ulong.MaxValue) { return(TomlValue.Create(v)); } else { throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter); } }
/// <summary>配列内の値の型が全て一致するか判定する。</summary> /// <param name="array">判定する配列参照。</param> /// <param name="iter">イテレータ。</param> /// <returns>配列情報。</returns> private ITomlValue CheckArrayValueType(List <ITomlValue> array, TomlInnerBuffer.TomlIter iter) { TomlValueType type = TomlValueType.TomlNoneValue; // 全ての要素の型が一致することを確認 if (array.Count > 0) { type = array[0].ValueType; for (int i = 1; i < array.Count; ++i) { if (type != array[i].ValueType) { throw new TomlAnalisysException(Resources.ARRAY_VALUE_DIFFERENT_ERR, iter); } } } // 配列を作成して返す switch (type) { case TomlValueType.TomlBooleanValue: var bools = array.Select(x => (bool)x.Raw).ToArray(); return(TomlValue.Create(bools)); case TomlValueType.TomlDateValue: var dates = array.Select(x => (TomlDate)x.Raw).ToArray(); return(TomlValue.Create(dates)); case TomlValueType.TomlFloatValue: var floats = array.Select(x => (double)x.Raw).ToArray(); return(TomlValue.Create(floats)); case TomlValueType.TomlIntegerValue: var longs = array.Select(x => (long)x.Raw).ToArray(); return(TomlValue.Create(longs)); case TomlValueType.TomlStringValue: var strings = array.Select(x => (string)x.Raw).ToArray(); return(TomlValue.Create(strings)); default: return(TomlValue.Create(array.ToArray())); } }
//----------------------------------------------------------------------------- // 数値/日付解析 //----------------------------------------------------------------------------- /// <summary>数値(日付/整数/実数)を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <returns>値。</returns> internal static ITomlValue GetNumberOrDateValue(this TomlInnerBuffer.TomlIter iter) { int year, hour; if (ConvertPartitionNumber(iter, 0, 4, out year) && iter.GetChar(4).ch1 == '-') { // 日付(年月日)を取得する return(TomlValue.Create(ConvertDateFormat(iter, year))); } else if (ConvertPartitionNumber(iter, 0, 2, out hour) && iter.GetChar(2).ch1 == ':') { // 日付(時分秒)を取得する return(TomlValue.Create(ConvertTimeFormat(iter, hour))); } else { // 数値(整数/実数)を取得する return(iter.GetNumberValue(false)); } }
//--------------------------------------------------------------------- // 定数リテラル解析 //--------------------------------------------------------------------- /// <summary>数値(定数)を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <param name="value">値(戻り値)</param> /// <returns>値が取得できたならば真。</returns> internal static bool AnalisysKeyword(this TomlInnerBuffer.TomlIter iter, out ITomlValue value) { // 真偽値(偽)を返す if (iter.RemnantLength >= 5) { if (iter.GetChar(4).ch1 == 'e' && iter.GetChar(3).ch1 == 's' && iter.GetChar(2).ch1 == 'l' && iter.GetChar(1).ch1 == 'a' && iter.GetChar(0).ch1 == 'f') { value = TomlValue.False; iter.Skip(5); return(true); } } if (iter.RemnantLength >= 4) { // 真偽値(真)を返す if (iter.GetChar(3).ch1 == 'e' && iter.GetChar(2).ch1 == 'u' && iter.GetChar(1).ch1 == 'r' && iter.GetChar(0).ch1 == 't') { value = TomlValue.True; iter.Skip(4); return(true); } // 正の無限値を返す if (iter.GetChar(3).ch1 == 'f' && iter.GetChar(2).ch1 == 'n' && iter.GetChar(1).ch1 == 'i' && iter.GetChar(0).ch1 == '+') { value = TomlValue.Create(double.PositiveInfinity); iter.Skip(4); return(true); } // 負の無限値を返す if (iter.GetChar(3).ch1 == 'f' && iter.GetChar(2).ch1 == 'n' && iter.GetChar(1).ch1 == 'i' && iter.GetChar(0).ch1 == '-') { value = TomlValue.Create(double.NegativeInfinity); iter.Skip(4); return(true); } // 正の非数値を返す if (iter.GetChar(3).ch1 == 'n' && iter.GetChar(2).ch1 == 'a' && iter.GetChar(1).ch1 == 'n' && iter.GetChar(0).ch1 == '+') { value = TomlValue.Create(double.NaN); iter.Skip(4); return(true); } // 負の非数値を返す if (iter.GetChar(3).ch1 == 'n' && iter.GetChar(2).ch1 == 'a' && iter.GetChar(1).ch1 == 'n' && iter.GetChar(0).ch1 == '-') { value = TomlValue.Create(-double.NaN); iter.Skip(4); return(true); } } if (iter.RemnantLength >= 3) { // 無限値を返す if (iter.GetChar(2).ch1 == 'f' && iter.GetChar(1).ch1 == 'n' && iter.GetChar(0).ch1 == 'i') { value = TomlValue.Create(double.PositiveInfinity); iter.Skip(3); return(true); } // 非数値を返す if (iter.GetChar(2).ch1 == 'n' && iter.GetChar(1).ch1 == 'a' && iter.GetChar(0).ch1 == 'n') { value = TomlValue.Create(double.NaN); iter.Skip(3); return(true); } } value = null; return(false); }
/// <summary>数値(整数/実数)を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <param name="numberSign">符号。</param> /// <returns>数値。</returns> private static ITomlValue Get10NumberValue(TomlInnerBuffer.TomlIter iter, bool numberSign) { ulong v = 0; bool ud = false; UTF8 c; int point = iter.Pointer; int digit = -1; int expo = -1; int exp_v = -1; bool ld_zero = false, lst_zero = false; // 仮数部を取得する while ((c = iter.GetChar(0)).ch1 != 0) { // 1. '_'の連続の判定 // 2. 数値の計算をする // 2-1. 数値の有効範囲を超えるならばエラー // 3. 小数点位置を取得する // 4. 指数部(e)を取得する if (c.ch1 == '_') { if (ud) // 1 { throw new TomlAnalisysException(Resources.UNDERBAR_CONTINUE_ERR, iter); } ud = true; } else if (c.ch1 >= '0' && c.ch1 <= '9') { if (v < ulong.MaxValue / 10) // 2 { v = v * 10 + (ulong)(c.ch1 - '0'); if (digit >= 0) { digit++; lst_zero = true; } else { ld_zero = true; } } else // 2-1 { throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter); } ud = false; } else if (c.ch1 == '.') // 3 { if (ld_zero && digit < 0) { digit = 0; } else if (ld_zero) { throw new TomlAnalisysException(Resources.MULTI_DECIMAL_ERR, iter); } else { throw new TomlAnalisysException(Resources.NO_LEADING_ZERO_ERR, iter); } } else if (c.ch1 == 'e' || c.ch1 == 'E') { expo = 0; // 4 break; } else { break; } iter.Skip(1); } // 一文字の数値もなければ None値を返す if (iter.Pointer == point) { return(TomlValue.Empty); } // 仮数部を取得する CalcExponentConvert(iter, digit, expo, out exp_v); if (digit < 0 && expo < 0) { // 整数値を取得する // // 1. 負の整数変換 // 2. 正の整数変換 if (numberSign) { if (v <= (ulong)long.MaxValue) // 1 { return(TomlValue.Create(-(long)v)); } else if (v == (ulong)long.MaxValue + 1) { return(TomlValue.Create(long.MinValue)); } else { throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter); } } else { if (v <= long.MaxValue) //2 { return(TomlValue.Create((long)v)); } else { throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter); } } } else { if (digit >= 0 && !lst_zero) { throw new TomlAnalisysException(Resources.NO_LAST_ZERO_ERR, iter); } // 実数値を取得する // // 1. 負の指数なら除算 // 2. 正の指数なら積算 // 3. 0の指数なら使用しない // 4. 値を保持 double dv = 0; if (exp_v < 0) { double abs_e = 1; // 1 for (int i = 0; i < Math.Abs(exp_v); ++i) { abs_e *= 10; } dv = (double)v / abs_e; } else if (exp_v > 0) { double abs_e = 1; // 2 for (int i = 0; i < Math.Abs(exp_v); ++i) { abs_e *= 10; } dv = (double)v * abs_e; } else { dv = (double)v; // 3 } if (dv <= double.MaxValue) // 4 { return(TomlValue.Create(numberSign ? (double)-dv : (double)dv)); } else { throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter); } } }
/// <summary>テーブル配列を作成する。</summary> /// <param name="iter">イテレータ。</param> /// <param name="table">カレントテーブル。</param> private void AnalisysTableArray(TomlInnerBuffer.TomlIter iter, TomlTable table) { // '.' で区切られたテーブル名を事前に収集する var keyPtr = iter.GetKeys(); // テーブル配列が閉じられているか確認 if (!iter.CloseTableArray()) { throw new TomlAnalisysException(Resources.TABLE_ARRAY_SYNTAX_ERR, iter); } // 最下層のテーブル以外のテーブル参照を収集する // // 1. テーブル参照を取得 // 2. エラーが有れば終了 // 3. 既に作成済みならばカレントを変更 // 4. 作成されていなければテーブルを作成し、カレントに設定 TomlTable curTable = table; TomlTable newTable = null; string keystr = ""; for (int i = 0; i < keyPtr.Count - 1; ++i) { keystr = keyPtr[i]; switch (curTable.SearchPathTable(keystr, out newTable)) // 1 { case 0: // 2 throw new TomlAnalisysException(Resources.TABLE_REDEFINITION_ERR, iter); case 1: curTable = newTable; // 3 break; default: newTable = new TomlTable(); // 4 curTable.AddKeyAndValue(keystr, newTable); curTable = newTable; break; } } // 最下層のテーブルは新規作成となる // // 1. 登録する名前(キー文字列)を取得 // 2. 親のテーブルに最下層のテーブル名が登録されている // 2-1. 登録されている名前のデータを取得する // 2-2. テーブル配列が登録されているならば、新規テーブルを作成し、カレントテーブルとする // 2-3. テーブル配列でないならばエラーとする // 3. 親のテーブルに最下層のテーブル名が登録されていない // 3-1. テーブル配列を作成し、テーブルを追加、追加されたテーブルが次のカレントテーブルになる keystr = keyPtr[keyPtr.Count - 1]; // 1 if (curTable.Contains(keystr)) // 2-1 { var val = curTable.Member(keystr); if (val.ValueType == TomlValueType.TomlTableArrayValue) // 2-2 { newTable = new TomlTable(); ((Array <TomlTable>)val).Add(newTable); } else // 2-3 { throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter); } } else { newTable = new TomlTable(); // 3-1 var newArr = TomlValue.Create(new TomlTable[] { newTable }); curTable.AddKeyAndValue(keystr, newArr); } // カレントのテーブルを作成したテーブルに変更 this.current = newTable; iter.SkipSpace(); }
/// <summary>数値(整数/実数/日付)を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <returns>値情報。</returns> private ITomlValue ConvertValue(TomlInnerBuffer.TomlIter iter) { ITomlValue value = null; // 値リテラルを解析する if (iter.AnalisysKeyword(out value)) { return(value); } // 複数ライン文字列を返す if (iter.RemnantLength >= 3) { // 複数ライン文字列を返す if (iter.GetChar(2).ch1 == '"' && iter.GetChar(1).ch1 == '"' && iter.GetChar(0).ch1 == '"') { iter.Skip(3); return(TomlValue.Create(iter.GetMultiStringValue())); } // 複数ライン文字列(リテラル)を返す if (iter.GetChar(2).ch1 == '\'' && iter.GetChar(1).ch1 == '\'' && iter.GetChar(0).ch1 == '\'') { iter.Skip(3); return(TomlValue.Create(iter.GetMultiLiteralStringValue())); } } // 数値/日付/文字列 if (iter.RemnantLength > 0) { switch (iter.GetChar(0).ch1) { case (byte)'"': // 文字列を取得する iter.Skip(1); return(TomlValue.Create(iter.GetStringValue())); case (byte)'\'': // リテラル文字列を取得する iter.Skip(1); return(TomlValue.Create(iter.GetLiteralStringValue())); case (byte)'#': // コメントを取得する iter.Skip(1); return(null); case (byte)'+': // 数値を取得する iter.Skip(1); return(iter.GetNumberValue(false)); case (byte)'-': // 数値を取得する iter.Skip(1); return(iter.GetNumberValue(true)); default: // 日付/数値を取得する return(iter.GetNumberOrDateValue()); } } else { throw new TomlAnalisysException(Resources.NOT_DEFINED_VALUE_ERR, iter); } }