Ejemplo n.º 1
0
        private static CalcValue BinRepeat(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            List <CalcValue> ret      = new List <CalcValue>();
            CalcNumber       numRight = (CalcNumber)right;
            int count = (int)numRight.Value;

            CalcObject _i = null;

            if (vars.ContainsVar("_i"))
            {
                _i = vars["_i"];
            }

            for (int i = 0; i < count; i++)
            {
                vars["_i"] = new CalcNumber(i);
                ret.Add(left.GetValue(vars, context));
            }

            if (_i != null)
            {
                vars["_i"] = _i;
            }

            return(new CalcList(ret.ToArray()));
        }
Ejemplo n.º 2
0
        // Returns the left raised to the power of the right.
        public static CalcValue BinPowerNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcNumber numLeft  = left as CalcNumber;
            CalcNumber numRight = right as CalcNumber;

            return(new CalcNumber((decimal)Math.Pow((double)(numLeft.Value), (double)(numRight.Value))));
        }
Ejemplo n.º 3
0
        // Adds two numbers.
        public static CalcValue BinPlusNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcNumber numLeft  = left as CalcNumber;
            CalcNumber numRight = right as CalcNumber;

            return(new CalcNumber(numLeft + numRight));
        }
Ejemplo n.º 4
0
        public static CalcValue BinIntDivideNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcNumber numLeft  = left as CalcNumber;
            CalcNumber numRight = right as CalcNumber;

            return(new CalcNumber(decimal.Floor(numLeft / numRight)));
        }
        public static void Load(int factPriority = FactPriority)
        {
            LoadPostFactorial(factPriority);

            numE  = new CalcNumber((decimal)Math.E);
            numPI = new CalcNumber((decimal)Math.PI);

            E  = new CLCodeFunction("e", (pars, vars, context) => numE);
            PI = new CLCodeFunction("pi", (pars, vars, context) => numPI);

            Abs          = new CLCodeFunction("abs", AbsFunction);
            Acos         = new CLCodeFunction("acos", AcosFunction);
            Acosh        = new CLCodeFunction("acosh", AcoshFunction);
            Asin         = new CLCodeFunction("asin", AsinFunction);
            Asinh        = new CLCodeFunction("asinh", AsinhFunction);
            Atan         = new CLCodeFunction("atan", AtanFunction);
            Atan2        = new CLCodeFunction("atan2", Atan2Function);
            Atanh        = new CLCodeFunction("atanh", AtanhFunction);
            Cos          = new CLCodeFunction("cos", CosFunction);
            Cosh         = new CLCodeFunction("cosh", CoshFunction);
            Sin          = new CLCodeFunction("sin", SinFunction);
            Sinh         = new CLCodeFunction("sinh", SinhFunction);
            Tan          = new CLCodeFunction("tan", TanFunction);
            Tanh         = new CLCodeFunction("tanh", TanhFunction);
            Ceiling      = new CLCodeFunction("ceiling", CeilingFunction);
            CopySign     = new CLCodeFunction("copysign", CopySignFunction);
            Floor        = new CLCodeFunction("floor", FloorFunction);
            Log          = new CLCodeFunction("log", LogFunction);
            Max          = new CLCodeFunction("max", MaxFunction);
            MaxMagnitude = new CLCodeFunction("maxmagnitude", MaxMagnitudeFunction);
            Min          = new CLCodeFunction("min", MinFunction);
            MinMagnitude = new CLCodeFunction("minmagnitude", MinMagnitudeFunction);
            Sign         = new CLCodeFunction("sign", SignFunction);
        }
        public static CalcValue SignFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length == 0)
            {
                throw new CLException("{!sign} requires a number.");
            }

            CalcNumber num = NumberAt(pars, 0, "!sign", vars, context);

            return(new CalcNumber(Math.Sign(num)));
        }
        // Returns the natural logarithm of the parameter.
        public static CalcValue LogFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length == 0)
            {
                throw new CLException("{!log} requires a number.");
            }

            CalcNumber num = NumberAt(pars, 0, "!floor", vars, context);

            return(new CalcNumber((decimal)Math.Log((double)num.Value)));
        }
Ejemplo n.º 8
0
        private static DiceDie FunctionDie(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length < 2)
            {
                throw new CLException("{!die} requires two params: A number and a value.");
            }

            CalcNumber num = NumberAt(pars, 0, "!die", vars, context);
            CalcValue  val = pars[1].GetValue();

            return(new DiceDie(num.Value, val));
        }
        public static CalcValue PostFactNumber(CalcObject param, CLLocalStore vars, CLContextProvider context)
        {
            CalcNumber num = param as CalcNumber;
            int        o   = 1;

            for (int i = 2; i < num.Value; i++)
            {
                o *= i;
            }

            return(new CalcNumber(o));
        }
        // Returns a number with magnitude x and sign of y
        public static CalcValue CopySignFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length < 2)
            {
                throw new CLException("{!copysign} requires two numbers.");
            }

            CalcNumber x = NumberAt(pars, 0, "!copysign", vars, context);
            CalcNumber y = NumberAt(pars, 1, "!copysign", vars, context);

            return(new CalcNumber((decimal)Math.CopySign((double)x.Value, (double)y.Value)));
        }
        // Returns the minimum value out of the list.
        public static CalcValue MinFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length == 0)
            {
                throw new CLException("{!min} requires numbers.");
            }

            decimal min = Decimal.MaxValue;

            for (int i = 0; i < pars.Length; i++)
            {
                CalcNumber num = NumberAt(pars, i, "!min", vars, context);
                min = Math.Min(min, num.Value);
            }

            return(new CalcNumber(min));
        }
Ejemplo n.º 12
0
        // Returns the quotient of a list's items over a number.
        public static CalcValue BinDivideList(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcList   lstLeft  = left as CalcList;
            CalcNumber numRight = right as CalcNumber;

            // We will *not* do string checking here
            // It's entirely possible someone writes a string divider and this function will use it.

            CalcValue[] lstRet = new CalcValue[lstLeft.Count];

            for (int i = 0; i < lstRet.Length; i++)
            {
                lstRet[i] = BinaryDivide.Run(lstLeft[i], numRight, vars, context);
            }

            return(new CalcList(lstRet));
        }
        // Returns the minimum value out of the list.
        public static CalcValue MinMagnitudeFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context)
        {
            if (pars.Length == 0)
            {
                throw new CLException("{!minmagnitude} requires numbers.");
            }

            decimal min = (decimal)Decimal.MinValue;

            for (int i = 0; i < pars.Length; i++)
            {
                CalcNumber num = NumberAt(pars, i, "!minmagnitude", vars, context);
                if (Math.Abs(num.Value) < min)
                {
                    min = num;
                }
            }

            return(new CalcNumber(min));
        }
Ejemplo n.º 14
0
        // Multiplies a string by a number.
        public static CalcValue BinTimesString(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcString strLeft  = left as CalcString;
            CalcNumber numRight = right as CalcNumber;

            int count = (int)numRight;

            if (count < 0)
            {
                throw new CLException("Strings cannot be repeated negative times.");
            }

            string strRet = "";

            for (int i = 0; i < count; i++)
            {
                strRet += strLeft;
            }

            return(new CalcString(strRet));
        }
Ejemplo n.º 15
0
        protected void Button1_Click(object sender, EventArgs e)
        {
            double CalcNumber;

            try
            {
                if (DropDownList1.SelectedValue == "Add")
                {
                    CalcNumber = Convert.ToDouble(resultTB.Text) +
                                 Convert.ToDouble(entryTB.Text);
                    ViewState["Number"] = CalcNumber.ToString();
                }

                else if (DropDownList1.SelectedValue == "Subtract")
                {
                    CalcNumber = Convert.ToDouble(resultTB.Text) -
                                 Convert.ToDouble(entryTB.Text);
                    ViewState["Number"] = CalcNumber.ToString();
                }

                else if (DropDownList1.SelectedValue == "Divide")
                {
                    CalcNumber = Convert.ToDouble(resultTB.Text) /
                                 Convert.ToDouble(entryTB.Text);
                    ViewState["Number"] = CalcNumber.ToString();
                }

                else
                {
                    CalcNumber = Convert.ToDouble(resultTB.Text) *
                                 Convert.ToDouble(entryTB.Text);
                    ViewState["Number"] = CalcNumber.ToString();
                }
            }
            catch (FormatException)
            {
                Response.Write("Please input a number.");
            }
        }
Ejemplo n.º 16
0
        // Multiplies a list by a number.
        public static CalcValue BinTimesList(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            CalcList   lstLeft  = left as CalcList;
            CalcNumber numRight = right as CalcNumber;

            // If it has a string, we'll just repeat the list multiple times.
            if (lstLeft.HasString())
            {
                int count = (int)numRight;
                if (count < 0)
                {
                    throw new CLException("Lists cannot be repeated negative times.");
                }

                CalcValue[] lstRet = new CalcValue[lstLeft.Count * count];

                for (int i = 0; i < count; i++)
                {
                    for (int j = 0; j < lstLeft.Count; j++)
                    {
                        lstRet[i * lstLeft.Count + j] = lstLeft[j];
                    }
                }

                return(new CalcList(lstRet));
            }
            else
            {
                // Otherwise we'll multiply everything by the number.
                CalcValue[] lstRet = new CalcValue[lstLeft.Count];

                for (int i = 0; i < lstRet.Length; i++)
                {
                    lstRet[i] = BinaryTimes.Run(lstLeft[i], numRight, vars, context);
                }
                return(new CalcList(lstRet));
            }
        }
Ejemplo n.º 17
0
        private static CalcValue KeepCompare(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars)
        {
            CalcList   lstLeft  = (CalcList)left;
            CalcNumber numRight = (CalcNumber)right;

            List <CalcValue> kept    = new List <CalcValue>();
            List <CalcValue> dropped = new List <CalcValue>();

            foreach (CalcValue val in lstLeft)
            {
                if (comp.CompareFunction(ValueOf(val), numRight.Value))
                {
                    kept.Add(val);
                }
                else
                {
                    dropped.Add(val);
                }
            }

            vars["_d"] = new CalcList(dropped.ToArray());
            return(new CalcList(kept.ToArray()));
        }
Ejemplo n.º 18
0
        private static CalcValue CompRerolls(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context, bool keep = false, bool recurse = false)
        {
            CalcList   lstLeft  = (CalcList)left;
            CalcNumber numRight = (CalcNumber)right;

            List <CalcValue> output = new List <CalcValue>();

            DiceContext dc        = null;
            int         limit     = 0;
            int         limitUsed = 0;

            // We need to get the limits if they've been set
            if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext))
            {
                dc    = (DiceContext)(context.Get(actualDiceContext));
                limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed);
                if (limit == 0)
                {
                    throw new LimitedDiceException();
                }
            }

            // Go through the list
            foreach (CalcValue val in lstLeft)
            {
                decimal value;
                if (val is CalcNumber valNum)
                {
                    value = valNum.Value;
                }
                else if (val is CalcList valList)
                {
                    value = valList.Sum();
                }
                else
                {
                    throw new CLException("Re-rolls only work with numeric values.");
                }

                // If it's a value we need to re-roll
                if (comp.CompareFunction(value, numRight.Value))
                {
                    // Keep the original value ("x" and "xr" operators)
                    if (keep)
                    {
                        output.Add(val);
                    }

                    // Now make another value (or recurse)
                    bool redo = true;

                    // Now figure out how many sides each die has...
                    int       sides = 0;
                    bool      list  = false;
                    CalcValue dSides;

                    CalcList lstSides = null;

                    if (val is DiceDie die)
                    {
                        dSides = die.Sides;

                        // (Are we using a list or a number for the sides?)
                        if (dSides is CalcNumber nSides)
                        {
                            sides = (int)(nSides.Value);
                        }
                        else if (dSides is CalcList lSides)
                        {
                            lstSides = lSides;
                            sides    = lSides.Count;
                            list     = true;
                        }
                    }
                    else
                    {
                        decimal valValue = 0;
                        if (val is CalcNumber nVal)
                        {
                            valValue = nVal.Value;
                        }
                        else if (val is CalcList lVal)
                        {
                            valValue = lVal.Sum();
                        }
                        else
                        {
                            throw new CLException("Reroll only works with numeric values.");
                        }

                        if (valValue < 0)
                        {
                            valValue *= -1;
                        }

                        sides =
                            (valValue <= 6) ? 6 :
                            (valValue <= 20) ? 20 :
                            (valValue <= 100) ? 100 :
                            (valValue <= 1000) ? 1000 :
                            (valValue <= 10000) ? 10000 :
                            (valValue <= 100000) ? 100000 :
                            (valValue <= 1000000) ? 1000000 :
                            (valValue <= 10000000) ? 10000000 :
                            (valValue <= 100000000) ? 100000000 :
                            (valValue <= 1000000000) ? 1000000000 : 2147483647;

                        dSides = new CalcNumber(sides);
                    }

                    // Now we can roll the dice!
                    Random rand = null;

                    if (context.ContainsDerived(typeof(Random), out Type actualRandom))
                    {
                        rand = (Random)(context.Get(actualRandom));
                    }
                    else
                    {
                        rand = new Random();
                    }

                    while (redo && limitUsed < limit)
                    {
                        int choice = rand.Next(sides);
                        limitUsed++;
                        decimal cValue = 0;

                        if (list)
                        {
                            CalcValue cVal = lstSides[choice];
                            if (cVal is CalcNumber cNum)
                            {
                                cValue = cNum.Value;
                                output.Add(new DiceDie(cValue, lstSides));
                            }
                            else if (cVal is CalcList cList)
                            {
                                cValue = cList.Sum();
                                output.Add(new DiceDie(cValue, lstSides));
                            }
                        }
                        else
                        {
                            cValue = choice + 1;
                            output.Add(new DiceDie(cValue, new CalcNumber(sides)));
                        }

                        // recursion?
                        if (recurse)
                        {
                            redo = comp.CompareFunction(cValue, numRight.Value);
                        }
                        else
                        {
                            redo = false;
                        }
                    }
                }
                else
                {
                    // The reroll comparison wasn't satisfied
                    output.Add(val);
                }
            }

            return(new CalcList(output.ToArray()));
        }
Ejemplo n.º 19
0
        // Returns the number, negated.
        public static CalcValue PreMinusNumber(CalcObject param, CLLocalStore vars, CLContextProvider context)
        {
            CalcNumber numParam = param as CalcNumber;

            return(new CalcNumber(-numParam));
        }
Ejemplo n.º 20
0
        private static CalcValue BinDice(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            int         limit = int.MaxValue;
            DiceContext dc    = null;

            // We need to get the limits if they've been set
            if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext))
            {
                dc    = (DiceContext)(context.Get(actualDiceContext));
                limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed);
                if (limit == 0)
                {
                    throw new LimitedDiceException();
                }
            }

            CalcNumber numLeft  = (CalcNumber)left;
            CalcNumber numRight = null;
            CalcList   lstRight = null;
            bool       list     = false;

            // Now figure out how many dice to roll...
            int count = (int)(numLeft.Value);

            // ... and whether or not it's within limits (including the limitation that it must be positive)
            if (count <= 0)
            {
                throw new CLException("The number of dice to roll must be positive.");
            }
            else if (count > limit)
            {
                count = limit;
            }

            // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻
            if (dc != null)
            {
                dc.PerFunctionUsed += count;
            }

            // Now figure out how many sides each die has...
            int sides = 0;

            // (Are we using a list or a number for the sides?)
            if (right is CalcNumber)
            {
                numRight = (CalcNumber)right;
                sides    = (int)(numRight.Value);
            }
            else if (right is CalcList)
            {
                lstRight = (CalcList)right;
                sides    = lstRight.Count;
                list     = true;
            }

            // ... and ensure it's at least one.
            if (sides < 1)
            {
                throw new CLException("Dice must have at least one side.");
            }

            // Now we can roll the dice!
            CalcValue[] ret = new CalcValue[count];

            Random rand = null;

            if (context.ContainsDerived(typeof(Random), out Type actualRandom))
            {
                rand = (Random)(context.Get(actualRandom));
            }
            else
            {
                rand = new Random();
            }

            for (int i = 0; i < count; i++)
            {
                int choice = rand.Next(sides);
                if (list)
                {
                    CalcValue val = lstRight[choice];
                    if (val is CalcNumber valNum)
                    {
                        ret[i] = new DiceDie(valNum.Value, lstRight);
                    }
                    else if (val is CalcList valList)
                    {
                        ret[i] = new DiceDie(valList.Sum(), lstRight);
                    }
                    else
                    {
                        throw new CLException("Dice must be numeric values."); // maybe I'll change this one day
                    }
                }
                else
                {
                    ret[i] = new DiceDie(choice + 1, new CalcNumber(sides));
                }
            }

            CalcList output = new CalcList(ret);

            // Add to roll history
            if (context.ContainsDerived(typeof(List <(string, CalcList)>), out Type actual))
            {
                List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual);
                history.Add(($"{left.ToCode()}d{right.ToCode()}", output));
            }

            return(output);
        }
Ejemplo n.º 21
0
        private static CalcValue CompUntil(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context)
        {
            int limit = int.MaxValue;

            DiceContext dc = null;

            // We need to get the limits if they've been set
            if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext))
            {
                dc    = (DiceContext)(context.Get(actualDiceContext));
                limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed);
                if (limit == 0)
                {
                    throw new LimitedDiceException();
                }
            }

            CalcNumber numLeft  = null;
            CalcList   lstLeft  = null;
            bool       list     = false;
            CalcNumber numRight = (CalcNumber)right;

            // Now figure out how many sides each die has...
            int sides = 0;

            // (Are we using a list or a number for the sides?)
            if (left is CalcNumber)
            {
                numLeft = (CalcNumber)left;
                sides   = (int)(numLeft.Value);
            }
            else if (left is CalcList)
            {
                lstLeft = (CalcList)left;
                sides   = lstLeft.Count;
                list    = true;
            }

            // ... and ensure it's at least one.
            if (sides < 1)
            {
                throw new CLException("Dice must have at least one side.");
            }

            // Now we can roll the dice!
            List <CalcValue> lstRet = new List <CalcValue>();

            Random rand = null;

            if (context.ContainsDerived(typeof(Random), out Type actualRandom))
            {
                rand = (Random)(context.Get(actualRandom));
            }
            else
            {
                rand = new Random();
            }

            CalcList output = null;
            Type     actual = null;

            for (int i = 0; i < limit; i++)
            {
                // First determine the value
                int        choice = rand.Next(sides);
                CalcNumber value  = null;
                if (list)
                {
                    CalcValue val = lstLeft[choice];
                    if (val is CalcList valList)
                    {
                        value = new DiceDie(valList.Sum(), lstLeft);
                    }
                    else if (val is CalcNumber valNum)
                    {
                        value = new DiceDie(valNum.Value, lstLeft);
                    }
                }
                else
                {
                    value = new DiceDie(choice + 1, new CalcNumber(sides));
                }

                // See if it satisfies the comparison
                if (comp.CompareFunction(value.Value, numRight.Value))
                {
                    vars["_u"] = value;

                    output = new CalcList(lstRet.ToArray());

                    // Add to roll history
                    if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual))
                    {
                        List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual);
                        history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output));
                        history.Add(($"Killed above roll:", ValToList(value)));
                    }

                    // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻
                    if (dc != null)
                    {
                        dc.PerFunctionUsed += i + 1;
                    }

                    return(output);
                }
                else
                {
                    lstRet.Add(value);
                }
            }

            vars["_u"] = new CalcNumber(0);
            output     = new CalcList(lstRet.ToArray());

            // Add to roll history
            if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual))
            {
                List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual);
                history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output));
            }

            // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻
            if (dc != null)
            {
                dc.PerFunctionUsed += limit;
            }

            return(output);
        }
Ejemplo n.º 22
0
        // Parses a single "operation chain"
        private static CalcObject ParseChain(List <CLObjectPiece> pieces)
        {
            // First, we can't parse an empty list.
            if (pieces.Count == 0)
            {
                throw new CLSyntaxException("Empty list received.", 0);
            }

            LinkedList <CLExpressionBuilder> exps = new LinkedList <CLExpressionBuilder>();
            CalcObject hold      = null;
            bool       valueLast = false;

            // Loop through all the pieces now.
            while (pieces.Count != 0)
            {
                CLObjectPiece piece = pieces[0];

                // Get the next value, if there is one.
                CalcObject obj = null;
                bool       err = false;

                // If it's a ()[]},
                if (piece.Type == CLObjectPieceType.Spacer)
                {
                    if (piece.Contents == "(")
                    {
                        if (!valueLast)
                        {
                            obj = ParseParentheses(pieces);
                        }
                        else
                        {
                            err = true;
                        }
                    }
                    else if (piece.Contents == "[")
                    {
                        if (!valueLast)
                        {
                            obj = ParseList(pieces);
                        }
                        else
                        {
                            err = true;
                        }
                    }
                    else /* ], ), }, , */
                    {
                        // Send control back up a parser level
                        break;
                    }
                }
                else if (piece.Type == CLObjectPieceType.FunctionName)
                {
                    if (!valueLast)
                    {
                        obj = ParseFunction(pieces);
                    }
                    else
                    {
                        err = true;
                    }
                }
                else if (piece.Type == CLObjectPieceType.Number)
                {
                    if (!valueLast)
                    {
                        obj = new CalcNumber(Decimal.Parse(piece.Contents));
                        pieces.RemoveAt(0);
                    }
                    else
                    {
                        err = true;
                    }
                }
                else if (piece.Type == CLObjectPieceType.String)
                {
                    if (!valueLast)
                    {
                        // Strip the quotes
                        string check = piece.Contents.Substring(1, piece.Contents.Length - 2);
                        // Parse special characters
                        check = check.Replace(@"\\", "\uF000")
                                .Replace(@"\n", "\n")
                                .Replace(@"\t", "\t")
                                .Replace(@"\", "")
                                .Replace("\uF000", @"\");
                        obj = new CalcString(check);
                        pieces.RemoveAt(0);
                    }
                    else
                    {
                        err = true;
                    }
                }

                if (err)
                {
                    throw new CLSyntaxException("Two consecutive values", piece.Position);
                }

                // If there's a value, put it in the most recent expression
                if (obj != null)
                {
                    valueLast = true;

                    // If there's no expression, just hold the value.
                    if (exps.Count == 0)
                    {
                        hold = obj;
                    }
                    else
                    {
                        // Put it on the most recent expression
                        CLExpressionBuilder exp = exps.Last.Value;
                        exp.Right = obj;
                    }

                    continue;
                }

                // Otherwise, this piece must be an operator.
                CLExpressionBuilder expNew = new CLExpressionBuilder();
                CLOperator          op     = null;
                valueLast = false;

                if (piece.Type == CLObjectPieceType.BinaryOperator)
                {
                    op = CLOperators.BinaryOperators[piece.Contents];
                }
                else if (piece.Type == CLObjectPieceType.PrefixOperator)
                {
                    op = CLOperators.PrefixOperators[piece.Contents];
                }
                else if (piece.Type == CLObjectPieceType.PostfixOperator)
                {
                    op = CLOperators.PostfixOperators[piece.Contents];
                }

                expNew.Operator = op;

                // If it's the first operator...
                if (exps.Count == 0)
                {
                    // ... use the held value if one exists
                    if (hold != null)
                    {
                        expNew.Left = hold;
                    }
                    exps.AddLast(expNew);
                }
                // Otherwise...
                else
                {
                    // For prefix operators we don't need to check priorities to the
                    // left. They can just stack on in.
                    if (op is CLPrefixOperator)
                    {
                        exps.Last.Value.Right = expNew;
                        exps.AddLast(expNew);
                    }
                    else
                    {
                        CLExpressionBuilder expOld  = null;
                        CLExpressionBuilder expNext = null;
                        // This code removes expressions from the stack that are a
                        // higher priority than the one being removed, or that are
                        // postfix.
                        while (exps.Count != 0)
                        {
                            expNext = exps.Last.Value;
                            if (
                                // The next expression is a postfix expression.
                                expNext.Operator is CLPostfixOperator ||
                                // The next expression on the stack is still higher
                                // priority
                                expNext.Operator.Priority > op.Priority ||
                                // The next expression on the stack is equal priority,
                                // but evaluated left-to-right
                                (expNext.Operator.Priority == op.Priority &&
                                 !CLOperators.IsFromRight(op.Priority))
                                )
                            {
                                expOld = exps.Last.Value;
                                exps.RemoveLast();
                                expNext = null;
                            }
                            else
                            {
                                break;
                            }
                        }

                        // The last removed expression becomes the left of this one.
                        // (If there's no such expression, then the right of the next
                        // expression on the stack becomes our left.)
                        if (expOld != null)
                        {
                            expNew.Left = expOld;
                        }
                        else
                        {
                            expNew.Left = expNext.Right;
                        }

                        // Then, this expression becomes the right of the next one.
                        if (expNext != null)
                        {
                            expNext.Right = expNew;
                        }

                        exps.AddLast(expNew);
                    }
                }

                pieces.RemoveAt(0);
            }

            if (exps.Count == 0)
            {
                return(hold);
            }
            else
            {
                return(exps.First.Value.Build());
            }
        }
Ejemplo n.º 23
0
        private static CalcValue KeepDropNumber(CalcList list, int count, bool keep, bool highest, CLLocalStore vars)
        {
            // Shortcuts
            if (list.Count == 0)
            {
                vars["_d"] = new CalcList(new CalcValue[0]);
                return(list);
            }
            if (count >= list.Count)
            {
                if (keep)
                {
                    vars["_d"] = new CalcList(new CalcValue[0]);
                    return(list);
                }
                else
                {
                    vars["_d"] = list;
                    return(new CalcList(new CalcValue[0]));
                }
            }
            else if (count <= 0)
            {
                if (keep)
                {
                    vars["_d"] = list;
                    return(new CalcList(new CalcValue[0]));
                }
                else
                {
                    vars["_d"] = new CalcList(new CalcValue[0]);
                    return(list);
                }
            }

            // The long way
            int found = 0;

            bool[]  action  = new bool[list.Count];
            decimal next    = highest ? decimal.MinValue : decimal.MaxValue;
            decimal current = next;

            decimal[] values = new decimal[list.Count];

            for (int i = 0; i < list.Count; i++)
            {
                // Get value of list item
                CalcValue  val = list[i];
                CalcNumber num = val as CalcNumber;
                if (num == null)
                {
                    num = ListToNum(val);
                }
                values[i] = num.Value;
            }

            while (found < count)
            {
                for (int i = 0; i < list.Count && found < count; i++)
                {
                    // If this is already one we found, skip it
                    if (action[i])
                    {
                        continue;
                    }

                    // Otherwise, if it's the next value, grab it
                    if (values[i] == current)
                    {
                        action[i] = true;
                        found++;
                    }

                    // Otherwise, check to see if it can be the next value
                    if (highest)
                    {
                        next = Math.Max(next, values[i]);
                    }
                    else
                    {
                        next = Math.Min(next, values[i]);
                    }
                }

                current = next;
                next    = highest ? decimal.MinValue : decimal.MaxValue;
            }

            // Now make the outputs
            CalcValue[] fits   = new CalcValue[count];
            CalcValue[] noFits = new CalcValue[list.Count - count];

            // Split the values into the two lists
            int fitCount   = 0;
            int noFitCount = 0;

            for (int i = 0; i < list.Count; i++)
            {
                if (action[i])
                {
                    fits[fitCount++] = list[i];
                }
                else
                {
                    noFits[noFitCount++] = list[i];
                }
            }

            if (keep)
            {
                vars["_d"] = new CalcList(noFits);
                return(new CalcList(fits));
            }
            else
            {
                vars["_d"] = new CalcList(fits);
                return(new CalcList(noFits));
            }
        }