//--------------------------------------------------------------------- // 文字解析 //--------------------------------------------------------------------- /// <summary>キー文字列の取得。</summary> /// <param name="buffer">内部バッファ。</param> /// <param name="iter">イテレータ。</param> /// <returns>キーリスト。</returns> internal static List <string> GetKeys(this TomlInnerBuffer.TomlIter iter) { var res = new List <string>(); while (iter.GetChar(0).ch1 > 0) { iter.SkipSpace(); // 1 var key = iter.GetKey(); // 2 if (key != null) { res.Add(key); if (iter.GetChar(0).ch1 != '.') // 3 { break; } iter.Skip(1); } else { break; } } return(res); }
/// <summary>値の解析を行う。</summary> /// <param name="iter">イテレータ。</param> /// <returns>値情報。</returns> private ITomlValue AnalisysValue(TomlInnerBuffer.TomlIter iter) { ITomlValue value = null; // インラインテーブル、配列、日付の確認 // // 1. インラインテーブルを解析する // 2. 配列を解析する // 3. 値を取得する iter.SkipSpace(); if (iter.GetChar(0).ch1 == '{') // 1 { iter.Skip(1); value = this.GetInlineTable(iter); } else if (iter.GetChar(0).ch1 == '[') // 2 { iter.Skip(1); value = this.GetValueArray(iter); } else { value = this.ConvertValue(iter); // 3 } return(value); }
//--------------------------------------------------------------------- // テーブル解析 //--------------------------------------------------------------------- /// <summary>テーブルを作成する。</summary> /// <param name="iter">イテレータ。</param> /// <param name="table">カレントテーブル。</param> private void AnalisysTable(TomlInnerBuffer.TomlIter iter, TomlTable table) { // '.' で区切られたテーブル名を事前に収集する var keyPtr = iter.GetKeys(); // テーブルが閉じられているか確認 if (!iter.CloseTable()) { throw new TomlAnalisysException(Resources.TABLE_SYNTAX_ERR, iter); } // テーブルを作成する // // 1. テーブル参照を取得 // 2. エラーが有れば終了 // 3. 既に作成済みならばカレントを変更 // 4. 作成されていなければテーブルを作成し、カレントに設定 TomlTable curTable = table; TomlTable newTable = null; foreach (var keystr in keyPtr) { 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; } } // 空白は読み捨てておく iter.SkipSpace(); // カレントのテーブルを設定 this.current = curTable; if (!this.current.IsDefined) { this.current.IsDefined = true; } else { throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter); } }
/// <summary>']' の後、次が改行/終端/コメントならば真を返す。</summary> /// <param name="iter">イテレータ。</param> /// <returns>改行/終端/コメントならば真。</returns> internal static bool CloseTable(this TomlInnerBuffer.TomlIter iter) { UTF8 c; // 空白を読み飛ばす iter.SkipSpace(); // ] の判定 if (iter.GetChar(0).ch1 != ']') { return(false); } iter.Skip(1); // 空白を読み飛ばす iter.SkipSpace(); // 文字を判定 c = iter.GetChar(0); return(c.ch1 == '#' || c.ch1 == '\r' || c.ch1 == '\n' || c.ch1 == 0); }
/// <summary>キー文字列を取得する。</summary> /// <param name="iter">イテレータ。</param> /// <returns>キー文字列。</returns> internal static string GetKey(this TomlInnerBuffer.TomlIter iter) { var buf = new List <byte>(); UTF8 c; // 空白を読み飛ばす iter.SkipSpace(); // 範囲の開始、終了位置で評価 // // 1. 一文字取得する // 2. キー使用可能文字か判定する // 3. " なら文字列としてキー文字列を取得する while ((c = iter.GetChar(0)).ch1 != 0) // 1 { if ((c.ch1 >= 'a' && c.ch1 <= 'z') || // 2 (c.ch1 >= 'A' && c.ch1 <= 'Z') || (c.ch1 >= '0' && c.ch1 <= '9') || c.ch1 == '_' || c.ch1 == '-') { c.Expand(buf); iter.Skip(1); } else if (c.ch1 == '"' && buf.Count <= 0) // 3 { iter.Skip(1); return(iter.GetStringValue()); } else { break; } } // バイトリストを文字列に変換して返す if (buf.Count > 0) { return(Encoding.UTF8.GetString(buf.ToArray())); } else { throw new TomlAnalisysException(Resources.KEY_ANALISYS_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> /// <param name="table">対象テーブル。</param> /// <param name="lastNoCheck">改行確認するならば真。</param> /// <returns>追加できたならば真。</returns> private bool AnalisysKeyAndValue(TomlInnerBuffer.TomlIter iter, TomlTable table, bool lastNoCheck) { // キー文字列を取得する // // 1. キー文字列を取得 // 2. キー以降の空白を読み飛ばす // 3. = で連結しているか確認 var keyPtr = iter.GetKeys(); // 1 iter.SkipSpace(); // 2 if (iter.GetChar(0).ch1 != '=') // 3 { throw new TomlAnalisysException(Resources.KEY_ANALISYS_ERR, iter); } // 値を取得する // // 1. 値が取得できるか // 2. 無効値であるか iter.Skip(1); var val = this.AnalisysValue(iter); // 1 if (val.ValueType == TomlValueType.TomlNoneValue) { return(false); // 2 } // 改行まで確認 if (!lastNoCheck && !iter.CheckLineEndOrComment()) { throw new TomlAnalisysException(Resources.KEY_VALUE_ERR, iter); } // '.' で指定されたテーブル参照を収集する // // 1. テーブル参照を取得 // 2. エラーが有れば終了 // 3. 既に作成済みならばカレントを変更 // 4. 作成されていなければテーブルを作成し、カレントに設定 TomlTable curTable = table; TomlTable newTable = null; for (int i = 0; i < keyPtr.Count - 1; ++i) { var 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; } } // 最終のテーブルに値を割り当てる var laststr = keyPtr[keyPtr.Count - 1]; if (!curTable.Contains(laststr)) { curTable.AddKeyAndValue(laststr, val); return(true); } else { throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter); } }