private ISqlNode ParseFunctionCall(ITokenizer t)
        {
            var name = t.GetNext();

            if (name.Type != SqlTokenType.Keyword && name.Type != SqlTokenType.Identifier)
            {
                throw ParsingException.UnexpectedToken(SqlTokenType.Identifier, name);
            }

            // "COUNT" "(" "*" ")"
            if (name.IsKeyword("COUNT"))
            {
                var openParen = t.Expect(SqlTokenType.Symbol, "(");
                var maybeStar = t.Peek();
                if (maybeStar.IsSymbol("*"))
                {
                    t.GetNext();
                    t.Expect(SqlTokenType.Symbol, ")");
                    return(new SqlFunctionCallNode
                    {
                        Location = name.Location,
                        Name = new SqlKeywordNode(name),
                        Arguments = new SqlListNode <ISqlNode> {
                            new SqlOperatorNode(maybeStar)
                        }
                    });
                }

                // It's not *, so put everything back, fallthrough, and let the rest of the parsing happen
                t.PutBack(openParen);
            }

            // TODO: "CONVERT" "(" <DataType>, <ScalarExpression> ("," <int>)? ")"
            // "CAST" "(" <ScalarExpression> "AS" <DataType> ")"
            if (name.IsKeyword("CAST"))
            {
                t.Expect(SqlTokenType.Symbol, "(");
                var first = ParseScalarExpression(t);
                t.Expect(SqlTokenType.Keyword, "AS");
                var type = ParseDataType(t);
                t.Expect(SqlTokenType.Symbol, ")");
                return(new SqlCastNode
                {
                    Location = name.Location,
                    Expression = first,
                    DataType = type
                });
            }

            // <Name> "(" <ScalarExpressionList> ")"
            return(new SqlFunctionCallNode
            {
                Location = name.Location,
                Name = Facts.IsBuiltInFunctionName(name.Value) ? (ISqlNode) new SqlKeywordNode(name.Value.ToUpperInvariant(), name.Location) : new SqlIdentifierNode(name),
                Arguments = ParseParenthesis(t, x => ParseList(x, ParseScalarExpression)).Expression
            });
        }
        public static SqlToken ExpectPeek(this ITokenizer ITokenizer, SqlTokenType type)
        {
            var found = ITokenizer.Peek();

            if (found.Type != type)
            {
                throw ParsingException.UnexpectedToken(type, found);
            }
            return(found);
        }
        public static SqlToken GetIdentifierOrKeyword(this ITokenizer ITokenizer)
        {
            var next = ITokenizer.GetNext();

            if (next.IsType(SqlTokenType.Identifier) || next.IsType(SqlTokenType.Keyword))
            {
                return(next);
            }
            throw ParsingException.UnexpectedToken(SqlTokenType.Identifier, next);
        }
        public static SqlToken Expect(this ITokenizer ITokenizer, SqlTokenType type, params string[] values)
        {
            var found = ITokenizer.GetNext();

            if (found.Type == type)
            {
                foreach (var value in values)
                {
                    if (found.Value == value)
                    {
                        return(found);
                    }
                }
            }

            throw ParsingException.UnexpectedToken(type, values, found);
        }