// 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());
            }
        }
 public CalcOperation(CalcObject left, CLOperator oper, CalcObject right)
 {
     Left     = left;
     Operator = oper;
     Right    = right;
 }