# File lib/chef_zero/solr/solr_parser.rb, line 120
      def read_single_expression
        token = next_token
        # If EOF, we have a problem Houston
        if !token
          parse_error(nil, "Expected expression!")

        # If it's an unary operand, build that
        elsif unary_operator?(token)
          operand = read_single_expression
          # TODO We rely on all unary operators having higher precedence than all
          # binary operators.  Check if this is the case.
          Query::UnaryOperator.new(token, operand)

        # If it's the start of a phrase, read the terms in the phrase
        elsif token == '"'
          # Read terms until close "
          phrase_terms = []
          until (term = next_token) == '"'
            phrase_terms << Query::Term.new(term)
          end
          Query::Phrase.new(phrase_terms)

        # If it's the start of a range query, build that
        elsif token == '{' || token == '['
          left = next_token
          parse_error(left, "Expected left term in range query") if !left
          to = next_token
          parse_error(left, "Expected TO in range query") if to != "TO"
          right = next_token
          parse_error(right, "Expected left term in range query") if !right
          end_range = next_token
          parse_error(right, "Expected end range '#{end_range}") if !['}', ']'].include?(end_range)
          Query::RangeQuery.new(left, right, token == '[', end_range == ']')

        elsif token == '('
          subquery = read_expression
          close_paren = next_token
          parse_error(close_paren, "Expected ')'") if close_paren != ')'
          Query::Subquery.new(subquery)

        # If it's the end of a closure, raise an exception
        elsif ['}',']',')'].include?(token)
          parse_error(token, "Unexpected end paren")

        # If it's a binary operator, raise an exception
        elsif binary_operator?(token)
          parse_error(token, "Unexpected binary operator")

        # Otherwise it's a term.
        else
          term = Query::Term.new(token)
          if peek_token == ':'
            Query::BinaryOperator.new(term, next_token, read_single_expression)
          else
            term
          end
        end
      end