private static Expression ParseEntityWithSuffix(TokenStream tokens)
        {
            Expression expression = ParseRootEntity(tokens);
            bool nextAllowed;
            bool keepGoing = true;
            string next = tokens.PeekValue();

            while (keepGoing)
            {
                switch (next)
                {
                    case "[":
                        // indexing or slicing
                        Token bracketToken = tokens.Pop();
                        List<Expression> sliceComponents = new List<Expression>();
                        nextAllowed = true;
                        while (!tokens.PopIfPresent("]"))
                        {
                            if (!nextAllowed) tokens.PopExpected("]"); // throws

                            if (tokens.IsNext(":"))
                            {
                                sliceComponents.Add(null);
                            }
                            else
                            {
                                sliceComponents.Add(Parse(tokens));
                            }
                            nextAllowed = tokens.PopIfPresent(":");
                        }
                        if (nextAllowed)
                        {
                            sliceComponents.Add(null);
                        }
                        if (sliceComponents.Count == 0)
                        {
                            throw new ParserException(bracketToken, "Unexpected token.");
                        }
                        else if (sliceComponents.Count == 1)
                        {
                            expression = new IndexExpression(expression, bracketToken, sliceComponents[0]);
                        }
                        else if (sliceComponents.Count <= 3)
                        {
                            expression = new SliceExpression(expression, bracketToken, sliceComponents);
                        }
                        else
                        {
                            throw new ParserException(bracketToken, "Slice expression has too many components.");
                        }
                        break;
                    case "(":
                        // function call
                        Token openParen = tokens.Pop();
                        nextAllowed = true;
                        List<Expression> args = new List<Expression>();
                        while (!tokens.PopIfPresent(")"))
                        {
                            if (!nextAllowed) tokens.PopExpected(")"); // throws
                            args.Add(Parse(tokens));
                            nextAllowed = tokens.PopIfPresent(",");
                        }

                        expression = new FunctionInvocation(expression, args);
                        break;
                    case ".":
                        // dot field
                        Token dotToken = tokens.Pop();
                        Token fieldToken = tokens.Pop();
                        if (!Util.IsIdentifier(fieldToken))
                        {
                            throw new ParserException(fieldToken, "Invalid field.");
                        }
                        expression = new DotField(expression, dotToken, fieldToken, fieldToken.Value);
                        break;
                    default:
                        keepGoing = false;
                        break;
                }
                next = tokens.PeekValue();
            }

            return expression;
        }
        private void SerializeFunctionInvocation(List<string> output, FunctionInvocation function)
        {
            if (function.Root is Variable)
            {
                // If it's uppercase, then it's a constructor invocation.
                string varName = ((Variable)function.Root).Value;
                if (varName[0] == varName.ToUpperInvariant()[0])
                {
                    output.Add("new ");
                }
            }

            this.SerializeExpression(output, function.Root);
            output.Add("(");
            for (int i = 0; i < function.Args.Length; ++i)
            {
                if (i > 0) output.Add(", ");
                this.SerializeExpression(output, function.Args[i]);
            }
            output.Add(")");
        }
 private void SerializeFunctionInvocation(List<string> output, FunctionInvocation functionInvocation)
 {
     SerializeExpression(output, functionInvocation.Root);
     output.Add("(");
     for (int i = 0; i < functionInvocation.Args.Length; ++i)
     {
         if (i > 0) output.Add(", ");
         SerializeExpression(output, functionInvocation.Args[i]);
     }
     output.Add(")");
 }