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

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

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

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

構文要素に対応するクラス(DomainOperation クラス:数値の単項演算・二項演算を表す)

    /// <summary>
    /// 数値の単項演算・二項演算を表すクラス:演算子といくつかの演算数で構成されます。
    /// </summary>
    internal class DomainOperation : DomainExpression
    {
        /// <summary>
        /// 演算子
        /// </summary>
        private readonly string op;
        /// <summary>
        /// 演算数の個数
        /// </summary>
        private readonly int arity;
        /// <summary>
        /// 第一の演算数
        /// </summary>
        private readonly DomainExpression exp1;
        /// <summary>
        /// 第二の演算数
        /// </summary>
        private readonly DomainExpression exp2;
        /// <summary>
        /// 演算子の優先順位のリスト
        /// </summary>
        private readonly string[][] precedence_list = [["*", "/", "%"], ["+", "-"]];
        /// <summary>
        /// 単項演算のコンストラクター
        /// </summary>
        /// <param name="op">演算子</param>
        /// <param name="exp">演算数</param>
        public DomainOperation(string op, DomainExpression exp)
        {
            this.op = op;
            arity = 1;
            this.exp1 = exp;
        }
        /// <summary>
        /// 二項演算のコンストラクター
        /// </summary>
        /// <param name="op">演算子</param>
        /// <param name="exp1">第一の演算数</param>
        /// <param name="exp2">第二の演算数</param>
        public DomainOperation(string op, DomainExpression exp1, DomainExpression exp2)
        {
            this.op = op;
            arity = 2;
            this.exp1 = exp1;
            this.exp2 = exp2;
        }
        /// <summary>
        /// 式を評価して無限自由モノイドの値を取得します。
        /// </summary>
        /// <param name="env">引数の値が記録されています。</param>
        /// <returns>式の値(無限自由モノイド)</returns>
        public Number Eval(Env<FreeMonoidUnion> env)
        {
            if (arity == 1)
            {
                switch (op)
                {
                    case "-":
                        return -exp1.Eval(env);
                    default:
                        return Number.Zero;
                }
            }
            else
            {
                switch (op)
                {
                    case "+":
                        return exp1.Eval(env) + exp2.Eval(env);
                    case "-":
                        return exp1.Eval(env) - exp2.Eval(env);
                    case "*":
                        return exp1.Eval(env) * exp2.Eval(env);
                    case "/":
                        return exp1.Eval(env) / exp2.Eval(env);
                    case "%":
                        return exp1.Eval(env) % exp2.Eval(env);
                    default:
                        return Number.Zero;
                }
            }
        }
        /// <summary>
        /// 演算子の優先順位
        /// </summary>
        /// <returns>演算子の優先順位</returns>
        private int precedence()
        {
            for (int i = 0; i < precedence_list.Length; i++)
            {
                if (precedence_list[i].Contains(op))
                {
                    return i;
                }
            }
            return -1;
        }
        /// <summary>
        /// 式を MonIter のコードの文字列に変換して取得します。
        /// </summary>
        /// <returns>MonIter のコードの文字列</returns>
        public string Print()
        {
            if (arity == 1)
            {
                if (exp1 is DomainOperation opexp && opexp.arity == 2)
                {
                    return $"{op}({exp1.Print()})";
                }
                else
                {
                    return $"{op} {exp1.Print()}";
                }
            }
            else
            {
                string exp1_str = exp1.Print();
                if (exp1 is DomainOperation opexp1 && opexp1.arity == 2 && precedence() < opexp1.precedence())
                {
                    exp1_str = $"({exp1_str})";
                }
                string exp2_str = exp2.Print();
                if (exp2 is DomainOperation opexp2 && opexp2.arity == 2 && precedence() < opexp2.precedence())
                {
                    exp2_str = $"({exp2_str})";
                }
                return $"{exp1_str} {op} {exp2_str}";
            }
        }
        /// <summary>
        /// 式を Python のコードの文字列に変換して取得します。
        /// </summary>
        /// <param name="yieldp">yield を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>Python のコードの文字列</returns>
        public string GeneratePython(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf)
        {
            return Print();
        }
        /// <summary>
        /// 式を C# のコードの文字列に変換して取得します。
        /// </summary>
        /// <param name="yieldp">yield return を表示するかどうか</param>
        /// <param name="typep">型名を表示するかどうか</param>
        /// <param name="indp">インデントを表示するかどうか</param>
        /// <param name="indcount">インデントの個数</param>
        /// <param name="perf">式のステートメントの文字列を変換する関数</param>
        /// <returns>C# のコードの文字列</returns>
        public string GenerateCS(bool yieldp, bool typep, bool indp, int indcount, Func<string, string> perf)
        {
            return Print();
        }
    }