非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

自由モノイドのイテレーター(19)

自由モノイドプログラミング言語の作成(MonIter バージョン1.2 仕様(3))

構文要素に対応するクラス(Prog クラス:プログラム全体)

Prog クラスに構文要素を作成する関数をまとめました。説明はコメントを見てください。

構文を説明する資料を自動的に作れるようにすれば良いのですが、難しいので、「ドキュメントコメント」(これは XML を作成してくれるものですが)のコメントを直接見てもらうことにします。

    /// <summary>
    /// プログラム全体を表すクラス:ステートメントのリストで構成されます。
    /// </summary>
    internal class Prog
    {
        /// <summary>
        /// プログラムを構成するステートメントのリスト
        /// </summary>
        private readonly IEnumerable<Statement> block;
        public Prog(IEnumerable<Statement> block)
        {
            this.block = block;
        }
        /// <summary>
        /// 式のステートメント:式で構成されます。
        /// </summary>
        /// <param name="expression"></param>
        /// <returns>式のステートメント</returns>
        public static ExpressionStatement ExpressionStatement(Expression expression)
        {
            return new ExpressionStatement(expression);
        }
        /// <summary>
        /// 関数の定義:関数名・パラメーターのリスト・関数本体の式で構成されます。
        /// </summary>
        /// <param name="name">関数名</param>
        /// <param name="list">パラメーターのリスト</param>
        /// <param name="exp">関数本体の式</param>
        /// <returns>関数の定義</returns>
        public static Definition Definition(Identifier name, IEnumerable<ParameterName> list, Expression exp)
        {
            return new Definition(name, list, exp);
        }
        /// <summary>
        /// パラメーターの名前
        /// </summary>
        /// <param name="name">パラメーターの名前</param>
        /// <returns>パラメーターの名前</returns>
        public static ParameterName ParameterName(string name)
        {
            return new ParameterName(name);
        }
        /// <summary>
        /// 関数(数値の列)の呼び出し:関数名・引数のリストで構成されます。
        /// </summary>
        /// <param name="name">関数名</param>
        /// <param name="list">引数(数値の列)のリスト</param>
        /// <returns>関数の呼び出し</returns>
        public static Function Function(Identifier name, IEnumerable<Expression> list)
        {
            return new Function(name, list);
        }
        /// <summary>
        /// 数値の項:数値の式で構成されます。
        /// </summary>
        /// <param name="exp">数値の式</param>
        /// <returns>数値の項</returns>
        public static Term DomainExpression(DomainExpression exp)
        {
            return new DomainUnit(exp);
        }
        /// <summary>
        /// 関数(数値)の呼び出し:関数名・引数のリストで構成されます。
        /// </summary>
        /// <param name="name">関数名</param>
        /// <param name="list">引数(数値)のリスト</param>
        /// <returns>関数の呼び出し</returns>
        public static DomainFunction DomainFunction(Identifier name, IEnumerable<DomainExpression> list)
        {
            return new DomainFunction(name, list);
        }
        /// <summary>
        /// 名前(関数名またはパラメーター名):名前を表す文字列で構成されます。
        /// </summary>
        /// <param name="name">名前を表す文字列</param>
        /// <returns>名前</returns>
        public static Identifier Identifier(string name)
        {
            return new Identifier(name);
        }
        /// <summary>
        /// 数値:数値を表す文字列で構成されます。
        /// </summary>
        /// <param name="number_string">数値を表す文字列</param>
        /// <returns>数値</returns>
        public static Number Number(string number_string)
        {
            return new Number(number_string);
        }
        /// <summary>
        /// 単項演算の式:演算子・演算数の式で構成されます。
        /// </summary>
        /// <param name="op">演算子</param>
        /// <param name="exp">演算数の式</param>
        /// <returns>単項演算の式</returns>
        public static DomainExpression Unary(string op, DomainExpression exp)
        {
            return new DomainOperation(op, exp);
        }
        /// <summary>
        /// 二項演算の式:演算子・二つの演算数の式で構成されます。
        /// </summary>
        /// <param name="op">演算子</param>
        /// <param name="exp1">第一の演算数の式</param>
        /// <param name="exp2">第二の演算数の式</param>
        /// <returns>二項演算の式</returns>
        public static DomainExpression Binary(string op, DomainExpression exp1, DomainExpression exp2)
        {
            return new DomainOperation(op, exp1, exp2);
        }
        /// <summary>
        /// プログラム全体の式を評価して無限自由モノイドの値を取得します。
        /// </summary>
        /// <returns>式の無限自由モノイドの値</returns>
        public FreeMonoid<int> Eval()
        {
            Env<FreeMonoidUnion> env = new Env<FreeMonoidUnion>();
            FreeMonoid<int> mon = FreeMonoid<int>.Zero;
            foreach (Statement st in block)
            {
                mon = st.Eval(env, this);
            }
            return mon;
        }
        /// <summary>
        /// プログラム全体から指定された名前の関数定義を検索して取得します。
        /// </summary>
        /// <param name="name">検索する関数の名前</param>
        /// <returns>関数の定義</returns>
        public Definition? FindDefinition(string name)
        {
            foreach (Statement st in block)
            {
                if (st is Definition def && def.Name == name)
                {
                    return def;
                }
            }
            return null;
        }
        /// <summary>
        /// MonIter のコードの文字列を取得します。
        /// </summary>
        /// <returns>MonIter のコードの文字列</returns>
        public string Print()
        {
            return string.Join("; ", block.Select(x => x.Print()));
        }
        /// <summary>
        /// インデントの文字列を取得します。
        /// </summary>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <returns>インデントの文字列</returns>
        private static string IndStr(bool indp, int indcount)
        {
            return new string(' ', 4 * (indp ? indcount : 0));
        }
        /// <summary>
        /// Python のコードの文字列を取得します。
        /// </summary>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>Python のコードの文字列</returns>
        public string GeneratePython(bool typep, Func<string, string> perf)
        {
            return ListGeneratePython(false, typep, false, 0, perf, "\r\n", block) + "\r\n";
        }
        /// <summary>
        /// リストの Python のコードの文字列を取得します。
        /// </summary>
        /// <typeparam name="T">リストの要素の型</typeparam>
        /// <param name="yieldp">yield を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <param name="sep">区切りの文字列</param>
        /// <param name="list">変換するリスト</param>
        /// <returns>Python のコードの文字列</returns>
        public static string ListGeneratePython<T>(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf, string sep, IEnumerable<T> list) where T: CodeGeneratable
        {
            string spc = IndStr(indp, indcount);
            return string.Join(sep, list.Select(x => spc + x.GeneratePython(yieldp, typep, indp, indcount, perf)));
        }
        /// <summary>
        /// C# のコードの文字列を取得します。
        /// </summary>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>C# のコードの文字列</returns>
        public string GenerateCS(bool typep, Func<string, string> perf)
        {
            return ListGenerateCS(false, typep, false, 0, perf, "\r\n", block) + "\r\n";
        }
        /// <summary>
        /// リストの C# のコードの文字列を取得します。
        /// </summary>
        /// <typeparam name="T">リストの要素の型</typeparam>
        /// <param name="yieldp">yield return を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <param name="sep">区切りの文字列</param>
        /// <param name="list">変換するリスト</param>
        /// <returns>C# のコードの文字列</returns>
        public static string ListGenerateCS<T>(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf, string sep, IEnumerable<T> list) where T : CodeGeneratable
        {
            string spc = IndStr(indp, indcount);
            return string.Join(sep, list.Select(x => spc + x.GenerateCS(yieldp, typep, indp, indcount, perf)));
        }
        /// <summary>
        /// C# の { と } で囲まれたブロックのコードの文字列を取得します。
        /// </summary>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="blockindp">ブロック内部にインデントを表示するかどうか</param>
        /// <param name="blockstr">ブロック内部のコードの文字列</param>
        /// <returns>C# のブロックのコードの文字列</returns>
        public static string GenerateCSBlock(int indcount, bool blockindp, string blockstr)
        {
            string spc = IndStr(true, indcount);
            string spc1 = "";
            if (blockindp)
            {
                spc1 = IndStr(true, indcount + 1);
            }
            return $"{spc}{{\r\n{spc1}{blockstr}{spc}}}";
        }
    }