Example #1
0
def parse(stream, register_map, register=None, parsers=None, state=None, builder=None, document_root=False):
    if builder is None:
        builder = TreeBuilder()

    # prepare the stream for parsing
    if isinstance(stream, str):
        stream = stream.decode('utf-8')
    stream = stream.replace('\r\n', '\n').replace('\r', '\n')  # normalize newlines

    if builder.root is None:
        if document_root is True:
            from document import DocumentNode
            builder.set_root(DocumentNode())
            hack_root = False
        else:
            from node import Node
            builder.set_root(Node())
            hack_root = True
    else:
        hack_root = False

    remembered_actual_node = builder.actual_node

    if register is None:
        register = Register([p for p in register_map])
        register.visit_register_map(register_map)
        if parsers is not None:
            register.add_parsers(parsers)

    opened_text_node = None

    whole_stream = stream
    while len(stream) > 0:
        assert isinstance(stream, unicode) == True, stream
        try:
            macro, stream_new = register.resolve_macro(stream, builder, state, whole_stream)
            if macro is not None and stream_new is not None:
                # negation in effect?
                if opened_text_node is not None and opened_text_node.content.endswith(NEGATION_CHAR):
                    # don't forget to eat negation char!
                    opened_text_node.content = opened_text_node.content[:-1]
                    raise ParserRollback("Negation resolved")

                logging.debug('Resolved macro %s' % macro)
                stream_new = register_map.pre_hooks(stream_new, macro, builder)
                macro.expand(builder=builder, state=state)
                register_map.post_hooks(macro, builder)
                stream = stream_new
                opened_text_node = None
            else:
                #logging.debug('Macro not resolved, add text node')
                node, stream = _get_text_node(stream, register, register_map, builder, state, opened_text_node=opened_text_node, whole_stream=whole_stream)
                if opened_text_node is None:
                    builder.append(node, move_actual=False)
                opened_text_node = node
        except (ParserRollback, MacroCallError):
            # badly resolved macro
            logging.debug('ParserRollback caught, forcing text char')
            node, stream = _get_text_node(stream, register, register_map, builder, state, True, opened_text_node=opened_text_node, whole_stream=whole_stream)
            if opened_text_node is None:
                builder.append(node, move_actual=False)
            opened_text_node=node

    if hack_root is True:
        builder.move_up()

    # make sure that we have ended where we have begun
    assert builder.actual_node == remembered_actual_node, "remembered %s, but actual node is %s" % (remembered_actual_node, builder.actual_node)

    if hack_root is False:
        return builder.root
    else:
        return builder.root.children