class HqueryEvaluationError(RuntimeError):

    @classmethod
    def must_be_node_set(cls, obj):
        if not is_node_set(obj):
            raise HqueryEvaluationError('Expected a node set, but found a(n) {0}'.format(obj.__class__.__name__))

    @classmethod
    def must_be_node_set_or_sequence(cls, obj):
        if not (is_node_set(obj) or is_sequence(obj)):
            raise HqueryEvaluationError('Expected a node set or sequence, but found a(n) {0}'.format(
                obj.__class__.__name__
            )) def string_value(obj):
    if is_tag_node(obj) or is_attribute_node(obj) or is_text_node(obj):
        return derive_text_from_node(obj, peek_context().preserve_space)
    elif is_number(obj) or is_boolean(obj):
        return str(obj)
    elif is_node_set(obj):
        return string_value(obj[0]) if len(obj) > 0 else ''
    elif is_sequence(obj):
        return ''.join(string_value(item) for item in obj)
    elif is_string(obj):
        return obj
    else:
        raise NotImplementedError('string_value not implemented for type "{0}"'.format(obj.__class__.__name__)) def is_string(obj):
    return is_a_string(obj) def debug_dump_anything(obj):
    if is_any_node(obj):
        result = debug_dump_node(obj)
    elif is_boolean(obj) or is_number(obj) or is_hash(obj) or is_array(obj):
        result = repr(obj)
    elif is_string(obj):
        result = u'string("{0}")'.format(obj)
    elif is_node_set(obj):
        result = u'node-set({0})'.format(', '.join(truncate_string(debug_dump_node(node), 20) for node in obj))
    elif is_sequence(obj):
        result = u'sequence({0})'.format(', '.join(truncate_string(debug_dump_anything(item), 20) for item in obj))
    else:
        raise RuntimeError("debug_dump_anything doesn't know how to handle {0}".format(obj.__class__.__name__))
    return debug_dump_long_string(result) def is_hash(obj):
    return obj.__class__.__name__ == 'JsonHash' def is_boolean(obj):
    return obj.__class__.__name__ == 'boolean' def is_number(obj):
    return obj.__class__.__name__ == 'number' def make_sequence(sequence):
    if not isinstance(sequence, list):
        sequence = [sequence]
    return sequence class HquerySyntaxError(ValueError):
    pass def is_tag_node(obj):
    return obj.__class__.__name__ == 'Tag' def is_text_node(obj):
    return obj.__class__.__name__ == 'NavigableString' def verbose_print(text, indent_after=False, outdent_before=False):
    if settings.VERBOSE:
        if outdent_before:
            pop_indent()
        if not is_a_string(text):
            text = text()
        print(u'{0}{1}'.format(' ' * indent_level, text), file=sys.stderr)
        if indent_after:
            push_indent()
import json
from hq.hquery.evaluation_error import HqueryEvaluationError
from hq.hquery.object_type import string_value, is_string, debug_dump_anything, is_hash, \
    is_boolean, is_number
from hq.hquery.sequences import make_sequence
from hq.hquery.syntax_error import HquerySyntaxError
from hq.soup_util import is_tag_node, is_text_node
from hq.verbosity import verbose_print



class JsonArray:

    def __init__(self, contents):
        if not isinstance(contents, list):
            raise HqueryEvaluationError('Attempted to construct a JSON array based on a(n) {0} object'.format(
                contents.__class__.__name__))
        self.contents = contents


    def __repr__(self):
        return 'ARRAY {0}'.format(repr(self.contents))


    def __str__(self):
        return json.dumps(self.contents)



class ComputedJsonArrayConstructor:

    def __init__(self):
        self.contents = None


    def set_contents(self, expression_fn):
        if self.contents is not None:
            raise HquerySyntaxError('computed JSON array constructor already has contents')
        self.contents = expression_fn


    def evaluate(self):
        return JsonArray([self._make_array_item(item) for item in make_sequence(self.contents())])


    def _make_array_item(self, value):

        if is_tag_node(value):