public static string CollectTree(NumExpr expr)
        {
            var collector = new NumExprTreeCollector();

            expr.Apply(collector);
            return(collector.Complete());
        }
        NumExpr GenerateImpl(int depthFrom, int maxDepth, int currDepth)
        {
            NumExpr expr;

            var caseNum = _rnd.Next(1, 4);

            while ((currDepth < depthFrom && caseNum < 3) ||
                   (currDepth >= maxDepth && caseNum > 2))
            {
                caseNum = _rnd.Next(1, 4);
            }

            switch (caseNum)
            {
            case 1: expr = NumExpr.Const(_rnd.Next(1, 100)); break;

            case 2: expr = NumExpr.Variable(_varNames[_rnd.Next(0, _varNames.Length)] + _rnd.Next(0, 10)); break;

            case 3:
            {
                expr = NumExpr.BinOp(
                    this.GenerateImpl(depthFrom, maxDepth, currDepth + 1),
                    this.GenerateImpl(depthFrom, maxDepth, currDepth + 1),
                    (NumOp)_rnd.Next(0, 3)
                    );
            }
            break;

            default:
                throw new NotImplementedException();
            }

            return(expr);
        }
        string GetChildStr(NumBinExpr curr, NumExpr child)
        {
            var    bin = child as NumBinExpr;
            string result;

            if (bin != null && _priorityByOp[curr.Kind] > _priorityByOp[bin.Kind])
            {
                result = $"({child.Apply(this)})";
            }
            else
            {
                result = child.Apply(this);
            }

            return(result);
        }
 public static NumExpr BinOp(NumExpr left, NumExpr right, NumOp op)
 {
     return(new NumBinExpr(left, right, op));
 }
        //public NumBinExpr Rel { get; set; }


        public NumBinExpr(NumExpr left, NumExpr right, NumOp kind)
        {
            this.Left  = left;
            this.Right = right;
            this.Kind  = kind;
        }