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