protected Parsed.Object TempDeclarationOrAssignment()
        {
            Whitespace();

            bool isNewDeclaration = ParseTempKeyword();

            Whitespace();

            Identifier varIdentifier = null;

            if (isNewDeclaration)
            {
                varIdentifier = (Identifier)Expect(IdentifierWithMetadata, "variable name");
            }
            else
            {
                varIdentifier = Parse(IdentifierWithMetadata);
            }

            if (varIdentifier == null)
            {
                return(null);
            }

            Whitespace();

            // += -=
            bool isIncrement = ParseString("+") != null;
            bool isDecrement = ParseString("-") != null;

            if (isIncrement && isDecrement)
            {
                Error("Unexpected sequence '+-'");
            }

            if (ParseString("=") == null)
            {
                // Definitely in an assignment expression?
                if (isNewDeclaration)
                {
                    Error("Expected '='");
                }
                return(null);
            }

            Expression assignedExpression = (Expression)Expect(Expression, "value expression to be assigned");

            if (isIncrement || isDecrement)
            {
                var result = new IncDecExpression(varIdentifier, assignedExpression, isIncrement);
                return(result);
            }
            else
            {
                var result = new VariableAssignment(varIdentifier, assignedExpression);
                result.isNewTemporaryDeclaration = isNewDeclaration;
                return(result);
            }
        }
        protected Expression ExpressionUnary()
        {
            // Divert target is a special case - it can't have any other operators
            // applied to it, and we also want to check for it first so that we don't
            // confuse "->" for subtraction.
            var divertTarget = Parse(ExpressionDivertTarget);

            if (divertTarget != null)
            {
                return(divertTarget);
            }

            var prefixOp = (string)OneOf(String("-"), String("!"));

            // Don't parse like the string rules above, in case its actually
            // a variable that simply starts with "not", e.g. "notable".
            // This rule uses the Identifier rule, which will scan as much text
            // as possible before returning.
            if (prefixOp == null)
            {
                prefixOp = Parse(ExpressionNot);
            }

            Whitespace();

            // - Since we allow numbers at the start of variable names, variable names are checked before literals
            // - Function calls before variable names in case we see parentheses
            var expr = OneOf(ExpressionList, ExpressionParen, ExpressionFunctionCall, ExpressionVariableName, ExpressionLiteral) as Expression;

            // Only recurse immediately if we have one of the (usually optional) unary ops
            if (expr == null && prefixOp != null)
            {
                expr = ExpressionUnary();
            }

            if (expr == null)
            {
                return(null);
            }

            if (prefixOp != null)
            {
                expr = UnaryExpression.WithInner(expr, prefixOp);
            }

            Whitespace();

            var postfixOp = (string)OneOf(String("++"), String("--"));

            if (postfixOp != null)
            {
                bool isInc = postfixOp == "++";

                if (!(expr is VariableReference))
                {
                    Error("can only increment and decrement variables, but saw '" + expr + "'");

                    // Drop down and succeed without the increment after reporting error
                }
                else
                {
                    // TODO: Language Server - (Identifier combined into one vs. list of Identifiers)
                    var varRef = (VariableReference)expr;
                    expr = new IncDecExpression(varRef.identifier, isInc);
                }
            }

            return(expr);
        }