import sys class StackFSM(object): """ Implement a finite state machine that uses a stack to manage state. """ def __init__(self): self._state_stack = [] def _current_state(self): if len(self._state_stack) > 0: return self._state_stack[-1] return None def update(self): fn = self._current_state() if fn is not None: fn() def push_state(self, state): self._state_stack.append(state) def pop_state(self): return self._state_stack.pop() class Parser(object): def __init__(self, document, output=None): self._document = document if output is None: output = sys.stdout self._output = output self._offset = 0 self._blanks = 0 self._fsm = StackFSM() def parse(self): self._fsm.push_state(self.text_state) while self._fsm._current_state() is not None: self._fsm.update() def text_state(self): if len(self._document) <= self._offset: self._fsm.pop_state() return line = self._document[self._offset] if line.strip() == '': self._blanks += 1 else: self._blanks = 0 if line.strip() == '```': self._fsm.pop_state() self._fsm.push_state(self.pre_state) self._output.write('
\n') self._offset += 1 elif line.startswith('* '): self._fsm.pop_state() self._fsm.push_state(self.list_state) self._output.write('
{}\n'.format(line[2:])) elif line.strip() == '': if self._blanks > 1: self._output.write('
{}
\n'.format(line)) self._offset += 1 def pre_state(self): if len(self._document) < self._offset: self.pop_state() return line = self._document[self._offset] if line.strip() == '```': self._fsm.pop_state() self._fsm.push_state(self.text_state) self._output.write('\n') self._offset += 1 elif line.startswith('* '): self._fsm.pop_state() self._fsm.push_state(self.list_state) self._output.write('